MySQL Memory Management, Memory Allocators, and Operating System
Learn more about memory management with MySQL.
Join the DZone community and get the full member experience.Join For Free
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 the 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
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.
One engineering team member 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 or jemalloc. From the mysqld point of view, everything is done correctly: there is no memory leak.
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 fulltext indexes introduced this flaw. As our engineer 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 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 the server will be incompatible with upstream, we prefer option 2 and look forward for the upstream fix of this bug.
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 to find out how to set it up at these pages here and here.
Published at DZone with permission of Sveta Smirnova, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.