I’m working currently on a server application which uses Glib and GObject system. I wanted to test it with valgrind against memory leaks, but the results had really scared me. I got tens of memory alignment errors and hundreds of bytes that leaked somewhere. After investigating the problem I found possible reasons and a solution.
The main problem is related to Glib and the way it allocates memory. It doesn’t use a pure C-like way which is based only on malloc & free. It rather uses something called “slice allocator”.
If you don’t know what the “slice allocator” is, I will quote some useful information from the Gnome Reference Manual.
Memory slices provide a space-efficient and multi-processing scalable way to allocate equal-sized pieces of memory, just like the original GMemChunks (from GLib <= 2.8), while avoiding their excessive memory-waste, scalability and performance problems.
To achieve these goals, the slice allocator uses a sophisticated, layered design that has been inspired by Bonwick's slab allocator. It uses posix_memalign() to optimize allocations of many equally-sized chunks, and has per-thread free lists (the so-called magazine layer) to quickly satisfy allocation requests of already known structure sizes. This is accompanied by extra caching logic to keep freed memory around for some time before returning it to the system. Memory that is unused due to alignment constraints is used for cache colorization (random distribution of chunk addresses) to improve CPU cache utilization. The caching layer of the slice allocator adapts itself to high lock contention to improve scalability.
If you are interested more information about “slice allocator” can be found here.
Unfortunately valgrind has some problems with the above concept and cannot detect if given blocks of memory were actually freed or not. When I tested a simple Glib application using g_slice_alloc with valgrind I got tens of memory alignment errors.
You can imagine how hard it can be to find some other errors/leaks which are not related to “slice alloc”, but are rather the fault of the programmer.
Having tens or hundreds of messages printed by valgrind can be quite misleading and in fact can hide some real problems. So how to avoid that? The simplest solution is always the best. Why can’t we disable “slice allocator”? Of course only for testing, later on when we are sure that there are no memory leaks in our application we can turn it on again.
In order to do this we have to set an environmental variable which disables the “slice allocator” and forces Glib to use normal mallocs.
There is no need to change anything in a source code, even the program doesn’t have to be recompiled.
Unfortunately “slice allocator” is not the only problem, the other one lies on the GObject side.
I don’t know why, but somebody invented a really “nice” function called g_type_init, which is responsible for initializing GObject type system. Ok, its great but why there is no g_type_deinit? Does anyone know where the whole memory that was previously initialized is freed? Valgrind doesn’t know that and again it complaints…
I managed to get rid of some of this errors by creating suppression files that are forcing valgrind to omit some of the most common errors. Of course it is not the best solution, but at least it can help to reduce the number of errors that are not the result of our fault.
The suppression file can be found below:
One thing is certain. The list of suppression will be expanding. The more I work with Glib the more suppressions I have to add. The current version of this file includes suppressions mainly from GHashTable, g_thread_init and g_type_init. If I find more possible leaks I will update this file.
Now it’s time to start valgrind with the whole configuration which allows to get rid of this Glib and GObject errors, the command is as follows:
G_SLICE=always-malloc valgrind --suppressions=build-aux/glib.supp --leak-check=full --show-reachable=yes ./our_program