When should I use g_object_unref()

After I read something about GLib memory I found out that there is a rule when to call g_free() function and this is because if there is const in front of a function, GTK internally takes care and if is not, then I have to call g_free() my self.

Now what I did not found is where and when should I call g_object_unref().
Is there any rule which apply to this function?

2 Likes

I think if you write your code in a high level language and use high level bindings to GTK you should not have to care much.

In plain C or with low level bindings it is not easy to get it correct, Valgrind may help to find leaks.

I wrote recently some text about this topic, but I am not sure if it is fully correct:

http://ssalewski.de/gtkprogramming.html#_legacy_program_layout

“We may wonder if we have to free widgets when we do not need them any longer. Indeed in C code that can be necessary in some cases. GTK uses reference counting for its objects, that is that each object has a reference counter. In C we can increase that counter to reference an object, that is to ensure that it is kept alive and is not destroyed by GTK. When we do not need that object any more we can decrease the reference counter. If the reference counter drops to zero then GTK destroys the object, that is GTK frees its memory and closes related resources. But often we do not have to really care for that. The reason for that is that GTK uses a special variant of reference counting: When we create a widget with a constructor like gtk_button_new() we get an instance which is market as “floating” indicating that the instance is not already owned by someone. Generally we insert each widget that we create into another widget, like a window or another container widget, and that container widget then takes ownership of its child. When the program terminates and the top level window is destroyed, then all its children are automatically freed. So we have not to care about all that memory management in this case. But there are exceptions to this process, so C programmers sometimes have to carefully check when they have to ref() and unref() resources. Fortunately high level languages like Nim or Python have a garbage collector which frees all objects when appropriate, so we have not to care for this. Nim with gintro supports even the new ARC memory management, which is deterministic and scope based: When a widget or another object goes out of scope it is immediately freed and all related resources are closed or released.”

3 Likes

GObject is a reference counted type. Reference counting is a form of garbage collection. Every time you take ownership of an object instance, you must acquire a reference to it—using g_object_ref(). Once you drop the ownership of that instance, you must release the reference you acquired—using g_object_unref().

If you get an object back from a function, and the documentation says “transfer full” or “newly allocated” or “a new reference”, then you need to call g_object_unref() to release the reference you’re given.

The API reference will always tell you if you’re dealing with something you own, or just a pointer to something that is owned by something else.

3 Likes

Not always. I can remember a few cases where it was not really clear from the API. Let us look on https://developer.gnome.org/gtk3/stable/GtkButton.html#gtk-button-new, it is not explicity stated, but of course in this case it is obvious if we know how GTK works.

2 Likes

I never said that you’ll get that information on every function.

I didn’t want to go down the details of widgets and objects with floating references—but, yes: the API reference will always tell you if what you get out of a constructor is an object with a full reference or and object with a full reference and a floating one. If the API reference doesn’t tell you how the memory is managed, then it’s a bug in the library.

2 Likes

This means that, when I see something like:

Returns

The newly created [GtkButton](https://developer.gnome.org/gtk3/stable/GtkButton.html) widget.

or

a new [GtkButton](https://developer.gnome.org/gtk3/stable/GtkButton.html)

or from properties:

Owner: GtkButton

I need to handle the reference my self.

And if I understand right, if I add it to a container as a child, then I do not need to drop its reference anymore because for the release process takes care the container now?

This means that, if I create a button has a floating point ( somewhere between 0 and 1).
If I add that button to a container ( window in this case) the reference grows to 1 and this happens because the container ( window) own it now.

Am I right?

EDIT:
This code when I click the Button:

#include <gtk/gtk.h>

static void btn_clbk ( GtkButton *button, gpointer data )
{
    ( void ) data;
    g_print ( "ref = %u\n", G_OBJECT ( button )->ref_count );

    g_object_ref ( button );
    g_print ( "ref = %d\n", G_OBJECT ( button )->ref_count );

    g_object_unref ( button );
    g_print ( "ref = %d\n", G_OBJECT ( button )->ref_count );

}

int main ( void )
{
    GtkWidget *window;
    GtkWidget *button;

    gtk_init ( NULL, NULL );

    window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    g_signal_connect ( window, "delete-event", gtk_main_quit, NULL );
    g_signal_connect ( window, "destroy",      gtk_main_quit, NULL );

    button = gtk_button_new();
    gtk_container_add( GTK_CONTAINER( window ), button );
    g_signal_connect ( button, "clicked", G_CALLBACK ( btn_clbk ), NULL );

    gtk_widget_show_all ( window );
    gtk_main ();
}

returns:

ref = 8
ref = 9
ref = 8

But I was expected to be:

ref = 1
ref = 2
ref = 1

If I understand Right, then this is what happens:

#include <gtk/gtk.h>

static void btn_clbk ( GtkButton *button, GtkBox *box )
{
    /*
        Now the removable_button has ref_count 1
        This is becouse the Box container owns a reference
        If we remove the button from the container (box)
        then the container drops the reference and ref_count is 0
        If ref_cont is 0 the button is destroyed
        If the button is destroyed we can not put it back in container
        To do that, ne need to take the ownership of the button before we remove the button
        To do that we call g_object_ref() and the ref_count increase to 2
        After That we can remove the button and the ref_count drops to 1
        Next, we put the button back, and the ref_count increase again from 1 to 2
        Last, We need to cal g_object_unref do drop it back to 1 the way it was before
    */
    g_return_if_fail ( GTK_IS_BUTTON ( button ) );
    g_return_if_fail ( GTK_IS_BOX ( box ) );

    GtkWidget *removable_button = g_object_get_data ( G_OBJECT ( box ), "btn_key" );
    static gint tmp_ref = FALSE;

    if ( GTK_IS_BUTTON ( removable_button ) )
    {
        if ( !tmp_ref )
        {
            /* increase ref_count from 1 to 2 */
            g_object_ref ( removable_button );
            g_print ( "\tThe ref_count is %u\n", G_OBJECT ( removable_button )->ref_count );
            gtk_container_remove ( GTK_CONTAINER ( box ), GTK_WIDGET ( removable_button ) );
            g_print ( "The removable_button was removed.\n" );
            g_print ( "\tThe ref_count is %u\n", G_OBJECT ( removable_button )->ref_count );
            tmp_ref = TRUE;
        }
        else
        {
            gtk_box_pack_end ( GTK_BOX ( box ), removable_button, FALSE, FALSE, 0 );
            g_print ( "The removable_button was Added and ref_count is: %u.\n", G_OBJECT ( removable_button )->ref_count );
            g_object_unref ( removable_button );
            g_print ( "\t\tAnd Now The ref_count is %u\n", G_OBJECT ( removable_button )->ref_count );
            tmp_ref = FALSE;
        }
    }
}

int main ( void )
{
    GtkWidget *window;
    GtkWidget *box;

    GtkWidget *button;
    GtkWidget *removable_button;

    gtk_init ( NULL, NULL );

    /* create the Window */
    window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );
    g_signal_connect ( window, "delete-event", gtk_main_quit, NULL );
    g_signal_connect ( window, "destroy",      gtk_main_quit, NULL );

    /* create the Box */
    box = gtk_box_new ( GTK_ORIENTATION_HORIZONTAL, 0 );
    gtk_widget_set_valign ( box, GTK_ALIGN_START );
    gtk_container_add ( GTK_CONTAINER ( window ), box );

    /* this button remove/brings the remuvable_button*/
    button = gtk_button_new_with_label ( "Click" );

    /* this button should be removed */
    removable_button = gtk_button_new_with_label ( "Remove" );

    /* The buttons have/are have Floating Point */

    /* here we check the clicked signal, and use the box as user data */
    g_signal_connect ( button, "clicked", G_CALLBACK ( btn_clbk ), box  );

    /* paching the buttons */
    /* Now the buttons does not have Floating Point anymore */
    gtk_box_pack_start ( GTK_BOX ( box ), button,           FALSE, FALSE, 0 );
    gtk_box_pack_end   ( GTK_BOX ( box ), removable_button, FALSE, FALSE, 0 );

    /* connect the removable_button with the Box */
    g_object_set_data ( G_OBJECT ( box ), "btn_key", removable_button );

    gtk_widget_show_all ( window );
    gtk_main ();
}

Output:

    The ref_count is 2
The removable_button was removed.
    The ref_count is 1
The removable_button was Added and ref_count is: 2.
        And Now The ref_count is 1

Anyway, I still do not understand why I got that Output in my previews replay :expressionless:

You should also check the is_floating() state of a widget:

https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#g-object-is-floating

When you create a new widget like a button its state should be floating, and generally ref count is 1. Note that ref_count is called a private field of gobject, so it is not really intended for inspection. If the widget is floating, and you add it to a container, than state should go to none floating. So the container takes ownership, you do not have to call g_object_unref() on it. But you would be free to call g_object_ref() g_object_unref() pairs on the object, maybe to keep it alive, for example when you temporary remove it from a container and later want to add it again.

The actual number of ref_count does not really matter, maybe when you add a button to a window that window references that widget multiple time – window is free to do that. What you may test is ref the button, add the button to the window and remove it again from the window. Then the effect of the window should cancel out, and ref count should be again 1 I guess.

I was indeed surprised by some ref count values myself when working on the Nim bindings, but finally I cared only for the 1/0 transition for the destroy process.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.