When users experience memory usage issues with any software, including MySQL®, their first response is to think that it’s a symptom of a memory leak. As this story will show, this is not always the case.
This story is about a bug.
All Percona Support customers are eligible for bug fixes, but their options vary. For example, Advanced+ customers are offered a HotFix build prior to the public release of software with the patch. Premium customers do not even have to use Percona software: we may port our patches to upstream for them. But for Percona products all Support levels have the right to have a fix.
Even so, this does not mean we will fix every unexpected behavior, even if we accept that behavior to be a valid bug. One of the reasons for such a decision might be that while the behavior is clearly wrong for Percona products, this is still a feature request.
A bug as a case study
A good recent example of such a case is PS-5312 – the bug is repeatable with upstream and reported at bugs.mysql.com/95065
This reports a situation whereby access to InnoDB fulltext indexes leads to growth in memory usage. It starts when someone queries a fulltext index, grows until a maximum, and is not freed for quite a long time.
Yura Sorokin from the Percona Engineering Team investigated if this is a memory leak and found that it is not.
When InnoDB resolves a fulltext query, it creates a memory heap in the function
fts_query_phrase_search
This heap may grow up to 80MB. Additionally, it has a big number of blocks (
mem_block_t
) which are not always used continuously and this, in turn, leads to memory fragmentation.
In the function
exit
, the memory heap is freed. InnoDB does this for each of the allocated blocks. At the end of the function, it calls
free()
which belongs to one of the memory allocator libraries, such as
malloc
jemalloc
. From the
mysqld
point of view, everything is done correctly: there is no memory leak.
However while
free()
should release memory when called, it is not required to return it back to the operating system. If the memory allocator decides that the same memory blocks will be required soon, it may still keep them for the
mysqld
process. This explains why you might see that
mysqld
still uses a lot of memory after the job is finished and all de-allocations are done.
This in practice is not a big issue and should not cause any harm. But if you need the memory to be returned to the operating system quicker, you could try alternative memory allocators, such as jemalloc. The latter was proven to solve the issue with PS-5312.
Another factor which improves memory management is the number of CPU cores: the more we used for the test, the faster the memory was returned to the operating system. This, probably, can be explained by the fact that if you have multiple CPUs, then the memory allocator can dedicate one of them just for releasing memory to the operating system.
The very first implementation of InnoDB full text indexes introduced this flaw. As our engineer Yura Sorokin found:
- The very first 5.6 commit which introduces Full Text Search Functionality for InnoDB WL#5538: InnoDB Full-Text Search Support – https://dev.mysql.com/worklog/task/?id=5538
- Implement WL #5538 InnoDB Full-Text Search Support, merge – https://github.com/mysql/mysql-server/commit/b6169e2d944 – also has this problem.
Options to fix
We have a few options to fix this:
- Change implementation of InnoDB fulltext index
- Use custom memory library like jemalloc
Both have their advantages and disadvantages.
Option 1 means we are introducing an incompatibility with upstream, which may lead to strange bugs in future versions. This also means a full rewrite of the InnoDB fulltext code which is always risky in GA versions, used by our customers.
Option 2 means we may hit flaws in the jemalloc library which is designed for performance and not for the safest memory allocation.
So we have to choose between these two not ideal solutions.
Since option 1 may lead to a situation when Percona Server will be incompatible with upstream, we prefer option 2 and look forward for the upstream fix of this bug.
Conclusion
If you are seeing a high memory usage by the
mysqld
process, it is not always a symptom of a memory leak. You can use memory instrumentation in Performance Schema to find out how allocated memory is used. Try alternative memory libraries for better processing of allocations and freeing of memory. Search the user manual for
LD_PRELOAD