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.

  1. TestKeySetMemory creates handles and kdbGets keysets in a loop and after waiting for 1 second - immediately closes the keyset + handle again before start over.
  2. TestKeySetMemoryWithDelayedClose also creates handles and fills keysets with kdbGets - 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)

Most upvoted comments

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 every free (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