活用 g_object_weak_ref 避免 memory leak

这是一个常见又恼人的问题 – Memory Leak 内存泄漏。常见的情况是软件用一段时间后,内存使用量肥大,在许多功能复杂的软件之中,不免会看到这类的情形。不过我们不能完全怪罪软件设计者〔虽然他们还是占很重要的因素〕,对程序开发者来说,要达成完全 Leak-free ,几乎是不可能的事,因为除了自己写的程序之外,各种 system call 都有可能造成 memory leak 的发生〔如 pango〕。

不过话说回来,system 里各种 library 所造成的 memory leak 毕竟还是少量,软件开发者所造成的问题占着大多数,一个真实的例子:从 Firefox 每次 release 就一直在修正 memory leak 就可以发现修也修不完。

来探讨 memory leak 的形成原因,顾名思义就是漏水,内存外漏产生了无法控制的内存区块。举个简单的例子:

void func()

{

  char *p;

 p = (char *)malloc(12);

  p = (char *)malloc(10);

 free(p);

}

此例的程序代码会出现 12 bytes 的 memory leak,因为第一次 malloc 取得的内存区块未被释放。换句话说,在第二次 malloc 之后,我们已经失去前一次内存区块的地址了,该区块对我们来说,已经是再也无法控制的内存区块〔因为不知道地址〕,但他仍然会在程序结束前活在那。如此一来,要是我们重复呼叫此 function ,每次都会造成 12 bytes 的浪费。

当然,这是明显可以看出 memory leak 存在的例子,有很多情况是很难发现问题的,尤其是在结构复杂的程序中。

有一个情况是这样,在 Gtk+ 程序的设计中,常会临时建立一个 structure 传给 Widget event 的 callback function,程序代码大致如下:

s = malloc(struct cb_s);

g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_func), s);

和传统的程序不同,我们不能在 g_signal_connect 之后就用 g_free() 去释放 s,因为在 menu_item 这 Widget 销毁之前,我们都有可能因事件触发而使用到 s。所以,这时就要用到一个特别的 g_object function:

void g_object_weak_ref(GObject *object, GWeakNotify notify, gpointer data);

这 g_object function 可以设定 object 被销毁后,将会呼叫什么 GWeakNotify function 做一些后续处理的动作。通常必需是自己设计一个 function 来呼叫,就如同 g_signal_connect 的 callback function 那样。不过在这例子中,可以有个漂亮的特殊用法:

g_object_weak_ref(menu_item, g_free, s);

将 Glib 的 g_free 当做 GWeakNotify function 来使用,是一个很漂亮的方式。在 menu_item destroy 之后,便会使用 g_free 将 s 给释放掉。如此就不会在,Widget 销毁后因为 s 而产生 memory leak 了

你可能感兴趣的:(活用 g_object_weak_ref 避免 memory leak)