GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Gtk memory management in a nutshell

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Example Code
Author Message
tadeboro
Never Seen the Sunlight


Joined: 23 Jul 2008
Posts: 1776
Location: Slovenia

PostPosted: Thu Dec 25, 2008 4:05 pm    Post subject: Gtk memory management in a nutshell Reply with quote

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 counting

We 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: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#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 GObject

The 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 GInitiallyUnowned

Looking 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.

Strings

Glib 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 properties

Operations 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 manipulation

When 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 parameters

The exactly the same principles apply as for the tree view store manipulation.

Test

My 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;-)

References
Glib

GObject

Gtk


Last edited by tadeboro on Tue Dec 08, 2009 7:01 pm; edited 3 times in total
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 918
Location: Falun, WI USA

PostPosted: Fri Dec 26, 2008 12:26 am    Post subject: Reply with quote

Very useful reference, moving to the example code forum...
EDIT: Thanks for fixing the typos.
Back to top
bruce89
GTK+ Geek


Joined: 19 Dec 2007
Posts: 60

PostPosted: Fri Jan 02, 2009 10:30 pm    Post subject: Re: Gtk memory management in a nutshell Reply with quote

tadeboro wrote:
My sample code suffers from memory leak. Can you find?


I think it's the use of g_strdup_printf in gtk_tree_model_set. The text is copied, but the original is not freed.
Provided solution is still there, but in white. Just highlight it -dreblen
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 918
Location: Falun, WI USA

PostPosted: Wed Feb 11, 2009 5:23 pm    Post subject: Reply with quote

Made this topic a sticky because it's a valuable reference.
If you want it un-stickied, I can do that too...
Back to top
caracal
GTK+ Guru


Joined: 21 Jun 2007
Posts: 205
Location: Wilkes Barre Pa

PostPosted: Thu Feb 12, 2009 4:20 am    Post subject: Reply with quote

Quote:
My sample code suffers from memory leak. Can you find?


Looks like the leak is on line 47.
Compiled with debug symbols:
gcc -g -o simple1 simple1.c `pkg-config --libs --cflags gtk+-2.0`

Ran valgrind:
valgrind --tool=memcheck --leak-check=yes ./simple1

Found proof of the leak:
malloc/free: 199,796 allocs, 158,155 frees,

Leak found here:
==20011== 45 bytes in 5 blocks are definitely lost in loss record 57 of 191
==20011== at 0x4025D2E: malloc (vg_replace_malloc.c:207)
==20011== by 0x48C3157: __vasprintf_chk (in /lib/tls/i686/cmov/libc-2.8.90.so)
==20011== by 0x47822BE: g_vasprintf (in /usr/lib/libglib-2.0.so.0.1800.2)
==20011== by 0x476E125: g_strdup_printf (in /usr/lib/libglib-2.0.so.0.1800.2)
==20011== by 0x8048F4A: main (simple1.c:47)

Provided solution is still there, but in white. Just highlight it.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Example Code All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP