-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Hello, our team has encountered an issue while using the mimalloc library:
Under certain conditions, the total committed memory does not decrease after calling std::vector::shrink_to_fit().
Background information:
Our development environment:
Windows 10, VS2022, C++17, mimalloc 2.1.7 release
We have overloaded the global new operator to our own memory allocator, GlobalMemory.
And internally, GlobalMemory uses mi_malloc_aligned() and mi_free() to perform its tasks.
Recently, while conducting memory optimization, I found that a vector should be released, so I wrote the release code:
some_data.clear();
some_data.shrink_to_fit();
// some_data is defined as std::vector<SomeStruct>
To my surprise, the total committed memory of the process did not decrease.
Through our project's internal memory statistics system, I clearly saw that 1.5GB was released, but in the Windows Task Manager, our total committed memory did not decrease.
(In our project, there are approximately 500 some_data instances, each about several megabytes, totaling 1.5GB)
Subsequently, I conducted a series of tests:
Test 1:
Changing the mimalloc dynamic library to a static library did not resolve the issue.
Test 2:
Searching for information on GitHub, I found in the README: "2025-06-09, v1.9.4, v2.2.4, v3.1.4 (beta): Some important bug fixes, including a case where OS memory was not always fully released."
I thought this was crucial, so I upgraded mimalloc to v2.2.4, BUT the issue persisted.
Test 3:
Instead of using mimalloc, I replaced mi_malloc_aligned() and mi_free() inside GlobalMemory with _aligned_malloc() and _aligned_free().
The issue disappeared, and I saw that the total committed memory of the process also decreased by approximately 1.5GB.
Test 4:
I attempted to debug and followed shrink_to_fit() into mi_free.
I found that the call chain is:
mi_free() -> mi_free_generic_mt() -> mi_free_block_mt() -> mi_free_block_delayed_mt()
At this point, I realized something: the allocating thread and the freeing thread were different, and in mi_free(), the bool is_local was false.
I suspected this was the cause, so I tried to make the freeing thread the same as the allocating thread, and it succeeded; the total committed memory correctly decreased.
Conclusion:
When calling mi_free(), if the calling thread is different from the allocating thread, there may be a bug that causes the release to fail.
I hope you can take a look at this issue.
Additionally, Christmas is approaching, and I wish you a Merry Christmas.