GLib 2.x has two allocation API:

g_slice_alloc() / g_slice_free()

/ g_malloc() / g_free()

The former is a slab allocator that has the ability, through environment variables/configuration, to fall back to the latter; the latter is a proxy for the system allocator, but had the ability to be expose a stable API that could be replaced by any allocator, through a virtual functions table set before any GLib function was called.

Internally, GLib uses a hodge-podge of calls to g_slice_alloc and g_malloc , depending on the age of the code in question.

With the introduction of constructors to replace initialization functions, the vtable approach for g_malloc() has been deprecated and cannot be used any more—there is no way for any API call to replace the allocator implementation at compile time.

Similarly, with the introduction of the use of -Bsymbolic in our default linker flags, we cannot use LD_PRELOAD and weak symbols to replace malloc() and free() at run time.

Additionally, various programming languages that have bindings for GLib have their own custom allocators, which have been optimized for the language requirements; the intersection between the completely opaque GLib allocation mechanism can lead to memory fragmentation, and difficulties in accounting the memory pressure.

Finally, while system allocators have improved their performance envelope in the time between the introduction of GSlice and now, custom allocators have seen further development, and are routinely used in complex projects that have special requirements for memory allocations. Similarly to the integration with other languages, the memory allocation strategy of GLib makes it completely opaque to the developers of these projects, and prevents tooling from inspecting memory usage, fragmentation, and pressure.

With the push to deprecate and replace g_slice_* with the system allocator currently ongoing in issue #1079, GLib is going to have a single, non-overridable allocator API that wraps the system allocator.

WARNING: This is a strawman. It's meant to be discussed and changed, and it does not represent a final design. Changes should be constructive/iterative.

A new allocator API

The basic approach would be to create a new Allocator API that provided the following entry points:

gpointer g_allocator_alloc ( const GAllocator * allocator , gsize block_size , gsize n_blocks ); gpointer g_allocator_alloc0 ( const GAllocator * allocator , gsize block_size , gsize n_blocks ); gpointer g_allocator_aligned_alloc ( const GAllocator * allocator , gsize block_size , gsize n_blocks , gsize alignment ); void g_allocator_free ( const GAllocator * allocator , gpointer mem_block ); void g_allocator_aligned_free ( const GAllocator * allocator , gpointer mem_block ); void g_allocator_realloc ( const GAllocator * allocator , gpointer mem_block , gsize old_size , gsize new_size );

The GAllocator data structure is a pointer to the allocator vtable, which replicates the API above.

Usage

Allocators are kept in a simple, thread-local stack that can be pushed and popped at will:

void g_allocator_push ( const GAllocator * allocator ); void g_allocator_pop ( void ); const GAllocator * g_allocator_get_current ( void );

Every data structure used by GLib will keep a backpointer of the current allocator at construction time, and will call the appropriate free function when releasing the resources it has; this allows to keep track of the appropriate allocator at run time whenever a new one gets pushed.

GLib provides a default allocator wrapping the system one:

const GAllocator * g_allocator_get_system ( void );

Which is also the default allocator pushed when we enter in the GLib constructor.

Changes in GLib

All allocated types in GLib will need to keep a backpointer to the GAllocator , and must never call g_allocator_get_system() itself.

Changes in external code

Similar changes to GLib should be applied to external code.

Language bindings and applications would be able to set up a new GAllocator instance, and push it at initialization/load.

Prior art

Most of the current design is inspired to the custom allocators crate in Rust.