歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux中內存洩漏的檢測(二)定制化的malloc/free

《linux中內存洩漏的檢測(一)最簡單的方法》介紹了最簡單的內存洩漏檢測方法,這種方法雖然簡單,卻有很多現實的問題,導致它不能用於實際的生產中。

直接使用這種方法肯定是不現實的,因為:

(1)把整個工程裡所有調用malloc/free的地方都改成my_malloc/my_free,代碼改動很大。

(2)通常動態庫和靜態庫的代碼是沒有權限修改的。

今天就來解決這個問題,動態地決定讓程序使用自己的還是系統的內存管理接口。

wrap選項

不希望修改產品代碼,那麼用於申請/釋放內存的接口還是malloc/free。
又想在接口中增加計數的功能,就要再實現一套用於申請/釋放內存的接口。新接口不能和malloc/free重名。這太矛盾了。

如果能自己定制一個malloc/free就好了。

幸好GCC也想到了這一點,給我們提供了wrap選項。
這是man ld得到的說明:

–wrap=symbol

Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol.

This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_symbol. If it wishes to call the system function, it should call __real_symbol.

Here is a trivial example:

>

void * __wrap_malloc (size_t c)
{
    printf ("malloc called with %zu\n", c);
    return __real_malloc (c);
}

If you link other code with this file using –wrap malloc, then all calls to malloc will call the function __wrap_malloc instead. The call to __real_malloc in __wrap_malloc will call the real “malloc” function.

You may wish to provide a __real_malloc function as well, so that links without the –wrap option will succeed. If you do this, you should not put the definition of __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve the call before the linker has a chance to wrap it to malloc.

我把這一大坨英文解釋一下(英語好的同學可以跳過):

wrapper在英文中是包裝的意思,也就是在已經存在無法修改的符號(通常是系統符號)的外面加一層定制化的包裝,這樣我們既可以重用原來的代碼,又可以加入新的功能。

當你對一個名為symbol符號使用wrap功能時,任何要用到symbol的地方實際使用的是__wrap_symbol符號

考慮到你的__wrap_symbol只是為了對symbol加一層包裝,有可能還是要用到真正的symbol,只需要要你的__wrap_symbol裡調用__real_symbol即可,因為任何用到__real_symbol的地方實際使用的是真正的symbol

也就是說,當你對一個名為symbol符號使用wrap功能時,會得到這樣的效果:

(1)當你調用symbol時實際調用的是__wrap_symbol

(2)當你調用__real_symbol時實際調用的是symbol

(3)可以把對symbol包裝的操作當在__wrap_symbol中,然後再讓__wrap_symbol調用__real_wrap,就相當於在使用symbol之前做了自己訂制的附加功能。

定制自己的malloc/free

看上去這個wrap功能正好符合我們的需求,我們來看看具體是怎麼使用。

(1)wrap既可以用於變量符號,也可以用於函數符號,但我們現在要用的只是函數符號,准確地說,就是malloc和free這兩個符號。

(2)這是一個在鏈接過程中起作用的選項,在鏈接選項中加上-Wl,--wrap,malloc -Wl,--wrap,free
(3)__wrap_malloc/__wrap_free函數實現

void * __wrap_malloc(int size)
{
    malloc_count++;
    return __real_malloc(size);
}

void __wrap_free(void *ptr)
{
    free_count++;
    __real_free(ptr);
}

(4)測試

int main()
{
    malloc_count = 0;
    free_count = 0;
    int *p1 = (int *)malloc(sizeof(int));
    int *p2 = (int *)malloc(sizeof(int));
    free( p1);
    if(malloc_count != free_count)
        printf("memory leak!\n");
    return 0;
}

(5)運行

gcc -o test main.c -Wl,--wrap,malloc -Wl,--wrap,free

分析

優點

(1)使用方便 — 不需要改產品代碼,只需要修改編譯選項即可完成。

(2)范圍全面 — wrap是個鏈接選項,對所有通過__wrap_malloc和__wrap_free鏈接到一起的文件都起作用,不論是靜態庫還是動態庫。

缺點

(1)該方法要求運行結束時對運行中產生的打印分析才能知道結果。

(2)只對C語言適用,不能應用於C++

(3)只能檢測是否洩漏,卻沒有具體信息,比如洩漏了多少空間

(4)不能說明是哪一行代碼引起了洩漏

改進

檢測方法有了初步改進,但不能滿足與此,預知下一步改進,且看下回分解

Copyright © Linux教程網 All Rights Reserved