Memory leak, dispose and finalize. What are the good practices?

Usually, GObjectClass.dispose is the right place to release resources. However, this is the guiding principal I think of when choosing dispose vs finalize.

Does my object create things in init that it expects to be there for the lifetime of the object? If so, and the data won’t cause circular references, I pair it with finalize. This is because it can be possible, particularly with async operations or GSourceFunc that a method could get called after your dispose has been called. So unless you’ve checked your internal state at the method boundaries, you might expect something like self->items to be non-NULL which it could be if it was cleared in dispose.

If I have things that can cause circular references, I try to put that in dispose and call g_object_run_dispose() from the “most important” object in the circular graph to cause circular references to break. Of course, we generally try to avoid circular reference, but that isn’t always possible.

If they are just data objects and having NULL values on fields are fine (the vast majority of objects), just clear state in dispose.

One case where I do both, however, is when I want to maintain symmetry between init/finalize to maintain those internal invariants, but also want to ensure related objects are released. In that case, I might use something like g_hash_table_remove_all() or g_ptr_array_remove_range() in dispose but actually free the containing structure in finalize.

Hope that helps!

2 Likes