GObject 引用计数的错误使用记录

在使用 GTK+ 编写浏览器插件 UI 的过程中发现部分资源在适合的时期一直不会被释放,追踪后发现是由于引用计数使用不当造成的,在此记录并提醒自己。

正常情况下,一个 GObject 被创建之后引用计数为 1,如果其它对象对其引用则增加一个引用计数,反次减小一个,当引用计数为 0 时对象会被销毁,资源被释放。

下面说一下我遇到的问题,

GtkWidget *tree_view = NULL;
GtkListStore *list_store = NULL;
 
list_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING,
                          G_TYPE_BOOLEAN);
tree_view = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view),
                          GTK_TREE_MODEL(list_sotre));
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view),
                          -1, "Name", gtk_cell_renderer_text_new(),
                          "text", COL_NAME, NULL);
/* 至此,即是我之前使用的代码,造成了内存泄漏, list_store 没有被释放,
   因为 gtk_tree_view_set_model 方法会增加一个引用计数。 */
g_object_unref(G_OBJECT(list_store));
/* 需要在使用后反引用一下。 */

你会发现在上面的代码中 gtk_cell_renderer_text_new 方法创建的 GtkCellRenderer 对象在被 gtk_tree_view_insert_column_with_attributes 方法引用后为什么不需要进行一次反引用呢?我们来看这两种类型的继承关系,

  GObject
   +----GtkListStore
  GObject
   +----GInitiallyUnowned
         +----GtkObject
               +----GtkCellRenderer
                     +----GtkCellRendererText
                     +----GtkCellRendererPixbuf
                     +----GtkCellRendererProgress
                     +----GtkCellRendererSpinner
                     +----GtkCellRendererToggle

从继承关系上可以看到 GtkObject 是继承是 GInitiallyUnowned 的,所有从 GInitiallyUnowned 继承的类型在创建后都是 floating 引用的,这种类型的引用其引用计数不为 1,当它被其它对象引用时,这个对象会先使用 g_object_is_floating 方法检查是否存在 floating 引用,存在则调用 g_object_ref_sink 增加引用计数,并去除 floating 引用标记,这时这个对象的引用计数为 1,也就意味着在后面不再需要显式的反引用了。

Over!

Leave a Reply

Your email address will not be published. Required fields are marked *