11 May 2009: Update
GtkTree(List)Store manipulation section has been updated a bit to better explain handling of boxed types
8 december 2009: Update
Reference counting is now explained from regular, consumer developer point of view
Hello.
Lately, there has been quite a few question asked about memory management on this forums and gtk mailing list, so I decided to sum up that I've learned while using gtk. Here we go.
Reference countingWe know that all Gtk objects are directly or indirectly derived from
GObject. One of the fundamental functionalities of GObject is (among others) reference counting, which helps programmer with memory management.
When the GObject is created, it has reference count of 1. This reference count can be increased or decreased with
g_object_ref and
g_object_unref functions respectively. When GObject's reference count drops to zero, it destroys itself and frees memory. But as always, there are some exceptions which will be discussed later.
Let's have a look at the life cycles of different objects. This is the code I'll be dissecting:
Code:
#include <gtk/gtk.h>
enum
{
COL_TEXT,
COL_IMG,
N_COLS
};
int
main( int argc,
char **argv )
{
GtkWidget *window;
GtkWidget *treeview;
GtkListStore *store;
GtkTreeIter iter;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
register gint i;
gtk_init( &argc, &argv );
/* Create main window */
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size( GTK_WINDOW( window ), 200, 150 );
g_signal_connect( G_OBJECT( window ), "destroy",
G_CALLBACK( gtk_main_quit ), NULL );
/* Create tree view and pack it into window */
treeview = gtk_tree_view_new();
gtk_container_add( GTK_CONTAINER( window ), treeview );
/* Create store and populate it with some data */
store = gtk_list_store_new( N_COLS, G_TYPE_STRING, GDK_TYPE_PIXBUF );
for( i = 0; i < 5; i++ )
{
GdkPixbuf *pixbuf;
pixbuf = gtk_widget_render_icon( GTK_WIDGET( treeview ),
GTK_STOCK_CANCEL,GTK_ICON_SIZE_BUTTON,
NULL );
gtk_list_store_append( store, &iter );
gtk_list_store_set( store, &iter,
COL_TEXT, g_strdup_printf( "Sample %d", i + 1 ),
COL_IMG, pixbuf,
-1 );
g_object_unref( G_OBJECT( pixbuf ) );
}
/* Set treeview's model */
gtk_tree_view_set_model( GTK_TREE_VIEW( treeview ),
GTK_TREE_MODEL( store ) );
g_object_unref( G_OBJECT( store ) );
/* Create display part of tree view - column 1 */
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new();
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( column ), renderer, TRUE );
gtk_tree_view_column_set_attributes( column, renderer,
"text", COL_TEXT, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW( treeview ), column );
/* Create display part of tree view - column 2 */
renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new();
gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( column ), renderer, TRUE );
gtk_tree_view_column_set_attributes( column, renderer,
"pixbuf", COL_IMG, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW( treeview ), column );
gtk_widget_show_all( window );
gtk_main();
return( 0 );
}
Direct descendants of GObjectThe first object we'll observe is GtkListStore, since it is
direct descendant of GObject.
When we create it with
gtk_list_store_new, it has reference count of 1. We own this reference, since we were the one who created this object. When we assign it to the tree view with
gtk_tree_view_set_model, tree view, tree view will also own list store. After assigning store to tree view, we don't need store anymore, so we remove our reference from store using
g_object_unref call (in some gtk tutorials/books this is described as "removing your own reference", since store is now owned solely by tree view). And when we quit our program, before tree view gets destroyed, it releases store which gets destroyed together with tree view.
This was the typical GObject life cycle. Now let's have a look at GtkWidget widget.
Descendants of GInitiallyUnownedLooking at the GtkWidget hierarchy, we'll find that one of the ancestors is GInitiallyUnowned. And this introduces a little twist in reference counting. When we create an object that inherits from GInitiallyUnowned, that object has reference count of 0, but has a floating reference. This is where calls name comes from: you don't own an initial reference on newly created object.
In order to put the things to their proper place, this floating reference needs to be sinked with
g_object_ref_sink, where sinking means converting floating reference to normal reference. After the sinking is done, these kind of objects behave exactly the same as normal GObjects.
So, our treeview's life goes through these phases:
gtk_tree_view_new() creates new object with floating reference (no one owns this reference);
gtk_container_add call adds our treeview into window which is now the owner of the tree view. When the program quits, toplevel window releases treeview (which gets destroyed).
The same principle applies to GtkTreeViewColumn and GtkCellRenderer.
What about our toplevel window? It is descendant of GInitiallyUnowned after all. GtkWindow has a special ability to sink it's own floating reference, and when we call
gtk_window_new, we get a window with a reference count of 1 and no floating reference. Or said otherwise, GtkWindow behaves like GObject, despite the fact that it's derived from GInitiallyUnowned.
StringsGlib library offers quite a few useful functions to manipulate strings. They are usually much easier to use than libc counterparts because they allocate memory for returned string for you. But you mustn't forget to free it after the resulting strings are not needed anymore. In short:
if API documentation says that the function returns newly allocated string, you must free it with g_free.
This section was short, but it is important to remember this for the next section.
GtkTree(List)Store data and object propertiesOperations related to storing data in stores and retrieving it can lead to quite large memory leaks, since these operations tend to be executed in loops. Operations on object properties are less problematic, but it still pays off to do them right.
GtkTree(List)Store manipulationWhen populating store with
gtk_tree_store_set, the data that we pass in is handled differently according to it's type:
- if the data passed in is object, then store takes ownership of it
- simple data types like integers and pointers are simply copied to the store (Important: when storing a pointer, only pointer is stored inside data store, data pointed to by the pointer is not copied!!)
- boxed types like strings and GdkColors are first copied and pointer to the copied data is stored inside data store
In example code, text gets copied and then pointer to that copied text is stored in first column of list store. Pixbuf on the other hand is not copied, it's reference count is increased by 1 instead and the pointer to pixbuf is stored in second column of our list store.
We also need to be careful when retrieving data from store. Again, there is difference when retrieving different types of data:
- when the object is retrieved, it's reference count is increased by 1 (we own one reference in this object)
- simple types are copied before handed to us
- boxed types are also coped before a pointer to data is handed to us
The main consequences of that are that we need to call g_object_unref on objects that we don't need anymore or free the data we retrieved from store if appropriate (you'll want to free strings and other boxed types when you don't need them any more).
Note: boxed types should be freed by the appropriate function. Generic way of doing it is to call
g_boxed_free on boxed type.
Manipulating object's parametersThe exactly the same principles apply as for the tree view store manipulation.
TestMy sample code suffers from memory leak. Can you find?
That's it. I hope you learned something new.
You are highly encouraged to post constructive comments, suggestions and of course corrections;-)
ReferencesGlibGObjectGtk