libelektra: KeySet close memory leak
While benchmarking the new elektrad I experienced memory leak symptoms.
The memory usage would go up after creating new handles and calling kdbGet() but never down after ksClose() and kdbClose().
My first suspicion was the mmap caching - which probably also causes memory leaks because the mmaped memory is never freed - but disabling caching by building with -DPLUGINS="ALL;-cache" did not solve my problem.
Steps to Reproduce the Problem
Go >= 1.13
I’ve created two tests in the go-elektra repo. Both create a test keyset with 100000 keys.
TestKeySetMemorycreates handles andkdbGetskeysets in a loop and after waiting for 1 second - immediately closes the keyset + handle again before start over.TestKeySetMemoryWithDelayedClosealso creates handles and fills keysets withkdbGets- but delays closing the handle and keyset until after all 20 keysets have been loaded. This immitates the behavior of the elektrad webserver.
Both tests wait for 20 seconds after finishing to allow the tester to see the memory consumption of the test via htop or similar tools.
The first test, which immediately closes the handle and keyset retains the same memory foot print over the length of the test.
The second test that starts closing the handles and keysets only after every keyset is ‘loaded’ never frees any memory. Even after forcing garbage collection and waiting for 20 seconds.
At the moment I’m clueless why the behavior of these tests differ.
You can run the tests by cloning the go-elektra repo and running these two commands in the ./kdb subdirectiry:
PKG_CONFIG_PATH=<PATH TO elektra.pc FILE> go test -run "^(TestKeySetMemory)\$"
PKG_CONFIG_PATH=<PATH TO elektra.pc FILE> go test -run "^(TestKeySetMemoryWithDelayedClose)\$"
Expected Result
Memory gets freed after kdbClose and ksClose
Actual Result
Memory does not get freed
System Information
- Elektra Version: master
- Operating System: Arch Linux
- Newest go-elektra version
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 32 (32 by maintainers)
I created #3183 for further testing/fixing.
I found one memleak (in a kdbGet return keys were not freed).
But the increasing number of “ksClose did NOT free 532 keys” is probably only the warnings collected in the parentKey. If you make NUM_RUNS higher, e.g. 100, it stagnates at some point, as the number of warnings is limited to 100. For me it goes to max. “ksClose did NOT free 901 keys”. Having a parentKey per handle would fix this problem.
You need to call
malloc_trim(0)after everyfree(read:ksDel). This forces glibc to immediately return the memory to the OS. This should fix the “weird behavior” you guys are seeing. Oh and have fun reading and digging into glibc 😃I will try to reproduce this in C until tomorrow