Reference counting
Contents
About
This document contains guidelines about when and how to use reference counting. If you wonder about the annotations in the gtk-doc comments of the examples (caller-owns, null-ok, callee-owns), take a look at these future ideas for gtk-doc and the documentation about GObject introspection.
The official GObject documentation about this can be found here.
Overview
- For deferred calls, delegates (callbacks), threads, workers
- Anything that returns an instance, needs to add a reference to it
- That includes singletons
- Constructors do this too, they just return a first reference
- Don't forget out parameters (by reference passing an instance)
For example when using a threadpool
- When passing to another part of the program of which you don't know how it'll be implemented in future
- The problem here is that you don't know what your colleague developers will do to implement it.
- In general assume that adding (and removing) a reference is relatively cheap. Unless you are referencing thousands of times, you shouldn't worry about performance impact at all.
- It's FALSE to think that NOT adding references if necessary is a memory leak fix. You don't fix memory leaks by introducing race conditions. You produce correct code instead. That's really the only way.
Caveats
GObject will not auto-detect cyclic references.
You can use the dispose method instead to clean up instance references, although I don't know myself how exactly this works (somebody please describe this). Read the section "Reference counts and cycles" of this document for more information about g_object_dispose.
You can use weak references in case your code requires a cyclic reference. In the GWeakNotify you can set the reference to NULL and make the implementation of A aware of its B property being NULL everywhere (for example).
These are examples of cyclic references even if your finalize (instance destructors) are correct at cleaning up resources:
A.B = ref (B) B.A = ref (A)
A.B = ref (B) A.C = ref (C) C.B = ref (B) C.A = ref (A)
list = new list() # if list.Add adds a reference to A (which it probably # should do. A weak reference where the GWeakNotify # removes the pointer from list might be a nice solution # too) list.Add (A) A.list = ref (list) or B.list = ref (list) A.B = ref (B)
Deferred calls
Threads
This is a typical worker thread example
typedef struct { GObject *instance; } ThreadInfo; static gpointer thread_func (gpointer data) { ThreadInfo *info = data; /* Perform work on info->instance */ gdk_threads_enter (); /* Update your UI, and use info->instance */ gdk_threads_leave (); g_object_unref (info->instance); g_slice_free (ThreadInfo, info); g_thread_exit (NULL); return NULL; }
The caller
static void MyMethod (GObject *instance) { ThreadInfo *info = g_slice_new (ThreadInfo); info->instance = g_object_ref (instance); g_thread_create (thread_func, info, TRUE/FALSE, NULL); }
Timeouts and idle-adds
Also read about Gdk and threading for the gdk_threads_enter.
static gboolean callback (gpointer user_data) { GObject *instance = user_data; gdk_threads_enter (); /* work with instance and don’t worry */ gdk_threads_leave (); return FALSE; }
The caller as timeout
static void MyMethod (GObject *instance) { g_timeout_add_full (G_PRIORITY_DEFAULT, 5 * 1000, callback, g_object_ref (instance), (GDestroyNotify) g_object_unref); }
The caller as idle
static void MyMethod (GObject *instance) { g_idle_add_full (G_PRIORITY_DEFAULT, callback, g_object_ref (instance), (GDestroyNotify) g_object_unref); }
In your library's API
Whenever you return an instance
You do want to opt for so-called caller-owns APIs. The reason for that is consistency and to improve thread safety (not solve). If all of your instance returning methods add a reference, then you are more sure that the user of your API wont finalize the instance that he got in another context than the one where he asked for the instance.
/** * my_type_get_something: * @self: a #MyType * * Returns something, you must unreference the returned value * * returns: (caller-owns): something **/ GObject* my_type_get_something (MyType *self) { return g_object_ref (self->something); }
For example
In this example we have two contexts. If my_type_get_something wouldn't have returned a reference, we would have created a race condition in case either context_a or context_b or the calling context where MyMethod runs would cause a finalization of self->something before the work of either context_a or context_b is done.
Now that we do add a reference, and since we also added a reference to my_something_owner at the creation of the worker threads, there's no race possible. If the calling context where MyMethod runs does a g_object_unref, then while either context_a or context_b are working on instance, instance will always be kept alive until the last one is finished with it.
Context A
static gpointer context_a (gpointer data) { ThreadInfo *info_a = data; instance = my_type_get_something (info_a->my_something_owner); /* The if is unnecessary because the API annotation doesn't claim * that null is ok. But this would be for a (null-ok) annotated * API then. * * A null-ok would have had a returns line like this: * returns: (caller-owns) (null-ok): something **/ if (instance) { /* Work with instance */ g_object_unref (instance); } g_object_unref (info_a->my_something_owner); g_slice_free (ThreadInfo, info_a); g_thread_exit (NULL); return NULL; }
Context B
static gpointer context_b (gpointer data) { ThreadInfo *info_b = data; instance = my_type_get_something (info_b->my_something_owner); if (instance) { /* Work with instance */ g_object_unref (instance); } g_object_unref (info_b->my_something_owner); g_slice_free (ThreadInfo, info_b); g_thread_exit (NULL); return NULL; }
The caller
static void MyMethod (MyType *a) { ThreadInfo *info_a = g_slice_new (ThreadInfo); ThreadInfo *info_b = g_slice_new (ThreadInfo); my_type_set_something (a, inject_something); /* Per wanted context we add a reference to a */ info_a->my_something_owner = g_object_ref (a); info_b->my_something_owner = g_object_ref (a); g_thread_create (context_a, info_a, TRUE/FALSE, NULL); g_thread_create (context_b, info_b, TRUE/FALSE, NULL); /* Each context has put its own 'reason to life' on a above. * This means that we can take our own reasons for a to life * away (a will be alive until both context_a and context_b * are done with it, as they'll take their own references). * * Because we implemented a correct, that also means that it * will itself keep its 'something' property working until it * itself gets finalized. Meaning that none of the instances * that either context_a nor context_b need will ever be in * finalized state. */ ... }
Out parameters
This follows the same rules as returning things. If you by-reference pass instances, you better make APIs that guarantee that references are added.
/** * my_type_fetch_me_into: * @self: a #MyType * @to_fetch: (out) (null-ok) (caller-owns): NULL or a location where to store what you want * * You must unreference @to_fetch after use. **/ void my_type_fetch_me_into (MyType *self, GObject **to_fetch) { if (to_fetch) { *to_fetch = g_object_ref (what_you_want); } }
Example:
static void MyMethod (...) { MyType *inst = ... GObject *what_i_want = NULL; my_type_fetch_me_into (inst, &what_i_want); /* Our out parameter is annotated as null-ok, * so we must check for it */ if (what_i_want) { /* Work with what_i_want */ g_object_unref (what_i_want); } }
The typical ones
Iterator
This example shows that all methods that return an instance, add a reference. The example shows how you use libgee in C. Gee is a library written in Vala that provides a group of typical collection types.
GeeCollection *list = ... GeeIterator *iter = gee_iterable_iterator (list); while (gee_iterator_next (iter)) { GObject *current = gee_iterator_get (iter); /* Work with current */ g_object_unref (current); } g_object_unref (iter);
Debugging reference count
You can get some hints on reference count debugging at ReferenceCountDebugging.