之前在meego性能優化團隊實習的時候,爲了提升APP啓動速度,我曾計算APP調用malloc的次數和耗時,並以此數據爲依據探討內存池對軟件優化的可能性。通俗地講,我須要將某些函數的調用重定向到咱們本身定義的替代函數中來,這樣的替代函數就叫作包裝函數(wrapper function)。對malloc這個具體的場景來講咱們不只須要hack函數的調用,還要獲取本來glibc定義的「real malloc」的句柄(函數指針)以使程序正常運行下去,固然若是這一切能夠在不須要從新編譯軟件的前提下完成就更好了。html
我總結了Linux環境下包裝函數的幾種實現方法:linux
1.LD_PRELOAD+dlsym性能優化
這對組合中,LD_PRELOAD完成了hack,而dlsym能夠幫組咱們獲取到real malloc。LD_PRELOAD是一個環境變量,它能夠影響程序的運行時的連接,讓咱們指定優先加載的動態連接庫。雖然這個方法沒法hack靜態連接的符號,不過還好gcc編譯的標準C函數大多包含在動態連接庫libc.so.6中,因此這個方法仍是可行的。app
my_malloc.cide
#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> void* malloc(size_t sz) { void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc"); printf("malloc\n"); return libc_malloc(sz); }
main.c函數
#include<stdio.h> #include <malloc.h> int main(int argc, char** argv) { int* ptr = (int *)malloc(sizeof(int)); free(ptr); return 0; }
gcc -o main.o -Wall -O2 main.c
gcc -o my_malloc.so -shared my_malloc.c -Wall -ldl -fPIC
export LD_PRELOAD=/path/.../my_malloc.so
./main.o性能
注意:
1.my_malloc.c中若是不加"#define _GNU_SOURCE",編譯時報錯「RTLD_NEXT undeclared」,由於glibc不會自動使用某些GNU extensions,因此須要定義這個宏啓用這些extensions。
2.LD_PRELOAD後面的so文件必定要使用絕對路徑或者把so文件放入LD_LIBRARY_PATH指定的目錄下,不然會找不到so文件。
3.LD_PRELOAD的做用效果是全局的,使用完後要及時恢復。優化
2.ld --wrap指針
適用:Linuxcode
ld有一個wrap選項,linux man的解釋是: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.
void * __wrap_malloc (size_t size) { printf ("malloc\\n"); return __real_malloc (size); }
全部對malloc的調用被解析爲調用__wrap_malloc,而__real_malloc則會被解析爲原始malloc函數。這種方法在gDEBugger上獲得了實際應用,gDEBugger是一個OpenGL Profiler,它能夠給出每一個OpenGL函數的調用次數使用時間等數據,它的實現方法就是爲全部OpenGL函數定義wrapper函數,在wrapper函數中添加統計代碼。
3.GCC Malloc Hook
gcc only malloc only
參考文獻:http://www.gnu.org/s/hello/manual/libc/Hooks-for-Malloc.html 這種方法其實有很強的侷限性,只針對使用gcc編譯的malloc,realloc,free等內存管理函數。gcc定義了一批函數指針變量,例如__malloc_hook指向「malloc」實際調用的函數,初始化時先保存真正的malloc函數指針而後將本身定義的malloc函數指針賦值給__malloc_hook。
/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> /* Prototypes for our hooks. */ static void my_init_hook (void); static void *my_malloc_hook (size_t, const void *); static void my_free_hook (void*, const void *); /* Override initializing hook from the C library. */ void (*__malloc_initialize_hook) (void) = my_init_hook; static void my_init_hook (void) { old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } static void * my_malloc_hook (size_t size, const void *caller) { void *result; /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ result = malloc (size); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call malloc, so protect it too. */ printf ("malloc (%u) returns %p\\n", (unsigned int) size, result); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; return result; } static void my_free_hook (void *ptr, const void *caller) { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ free (ptr); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call free, so protect it too. */ printf ("freed pointer %p\\n", ptr); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } int main () { ... }