by greenavocado | 2025-12-08 00:28:03+00:00
For situations where you do want to handle allocation failure, GLib provides g_try_malloc and related functions that can return NULL. The key insight is making the common case automatic and the exceptional case explicit. The g_new macro is particularly nice because it is type-aware. Instead of writing g_malloc of sizeof times count and then casting, you write g_new of type and count, and it handles the sizing and casting automatically while checking for overflow in the multiplication.

Reference counting is another critical component of GLib's memory management, particularly for objects. The GObject system, which is GLib's object system for C, uses reference counting to manage object lifetimes. Every object has a reference count starting at one when created. When you want to keep a reference to an object, you call g_object_ref. When you are done with it, you call g_object_unref. When the reference count reaches zero, the object is automatically destroyed. This is the same model used by shared_ptr in C++ or reference counting in Python, but implemented in pure C.

This also integrates with the autoptr system. Many GLib types are reference counted, and their cleanup functions simply decrement the reference count. This means you can declare a local variable with g_autoptr, the reference count stays positive while you use it, and when the variable goes out of scope the reference is automatically released. If you were the last holder of that reference, the object is freed. If other parts of the code still hold references, the object stays alive. This solves the resource sharing problem that makes manual memory management so difficult in C.

GLib also provides memory pools through GMemChunk and the newer slice allocator, though the slice allocator is being phased out in favor of standard malloc since modern allocators have improved significantly. The concept was to reduce allocation overhead and fragmentation for programs that allocate many small objects of the same size. You create a pool for objects of a specific size and then allocate from that pool quickly without going through the general purpose allocator. When you are done with all objects from that pool, you can destroy the entire pool at once. This pattern shows up in many high-performance C programs but GLib provided it as a reusable component.

The error handling story in GLib deserves special attention because it demonstrates how automatic cleanup enables better error handling patterns. The GError type is a structure that carries error information including a domain, a code, and a message. Functions that can fail take a GError double pointer as their last parameter. If the function succeeds, it returns true or a valid value and leaves the error NULL. If it fails, it returns false or NULL and allocates a GError with details about what went wrong. The calling code checks the return value and if there was an error, examines the GError for details.

The critical part is that GError is automatically freed when declared with g_autoptr. You can write a function that calls ten different operations, each of which might set an error, and you can check each one and return early if something fails, and the error is automatically freed on all code paths. You never leak the error message string, never double-free it, never forget to free it. This is a massive improvement over traditional C error handling where you either ignore errors or write incredibly tedious cleanup code with goto statements jumping to labels at the end of the function.

The GNOME developers could have switched to C++ or Rust or any modern language, but instead they invested in making C excellent at what C is good at. They added just enough infrastructure to eliminate the common pitfalls without fundamentally changing the language. A C programmer can read GLib code and understand it immediately because it is still just C. The auto macros are syntactic sugar over a compiler attribute, not a new language feature requiring a custom compiler.

This philosophy aligns pretty well with what the F-35 programmers want: the performance and predictability of C with the safety of automatic resource management. No hidden allocations, no virtual dispatch overhead, no exception unwinding cost, no template instantiation bloat. Just deterministic cleanup that happens exactly when you expect it to happen because it is tied to lexical scope, which is something you can see by reading the code.

I found it sort of surprising that the solution to modern C was not a new language or a massive departure from traditional practices. The cleanup attribute has been in GCC since 2003. Reference counting has been around forever. The innovation was putting these pieces together in a coherent system that feels natural to use and composes well.

Sometimes the right tool is not the newest or most fashionable one, but the one that solves your actual problem with the least additional complexity. GLib proves you can have that feature in C, today, with compilers that have been stable for decades, without giving up the simplicity and predictability that makes C valuable in the first place.