這幾天多個版本出現了多個內存泄漏問題-----------------------------------------怎么辦????
Q1:進程調用某庫函數分配內存不釋放, 但是在進程退出時,統一釋放內存,valgrind 檢查不出來,但是頻繁調用庫函數會耗盡內存。怎么快速定位那個庫函數導致!!!!!除了看源碼這種sa辦法
Q2:某些設備不支持跑valgrind 怎么辦??-
目前C&C++ 動態分配內存都是使用malloc-free new-delete
所以第一個方法是 每次分配內存時先記錄下來 釋放時記錄下來 這樣一對比就出來。。。or malloc記錄地址 free 去掉記錄地址
最后剩下的就是 沒有釋放的。。。。
第二個方法就是hook malloc了
http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Hooks-for-Malloc.html
http://goog-perftools.sourceforge.net/doc/tcmalloc.html
再就是 http://jemalloc.net/jemalloc.3.html#arena.i.chunk_hooks
再或者是:https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Debugging-Options.html#index-fsanitize_003daddress-593
第三個:malloc是一個weak symbol,所以直接寫一個malloc同名函數就行,同名函數中可以通過符號 __libc_malloc,這個符號直接指向malloc的實現部分
--------------->GCC wrap
ld中有一個選項 –wrap,當查找某個符號時,它優先先解析__wrap_symbol, 解析不到才去解析symbol。
好像對C++的new不起作用。
extern void *__libc_malloc(size_t size); void* malloc (size_t size) { // do your stuff { } // call the original malloc return __libc_malloc(size); }
再就是mtrace 了
再就是對比之前版本---看下這個版本改了什么了。。。再或者就是看覆蓋率,那些沒有跑到,然后review代碼了。。。
還要啥方法?????????????????????

/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> #include<stdio.h> #include<stdlib.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 *); /* Variables to save original hooks. */ static void *(*old_malloc_hook)(size_t, const void *); static void *(*old_free_hook)(size_t, const void *); extern void *(*malloc_hook)(size_t, const void *); extern void *(*free_hook)(size_t, const void *); static void my_init (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; } main () { my_init (); int *p = malloc(100); p[1] = 23; p[2] = 32; free(p); p = NULL; }
目前使用malloc hook 解決了 不能跑vlagrind的問題;但是只是知道有內存泄漏,那怎樣知道內存泄漏時那個函數觸發的呢??
繼續研究堆棧回溯!!!
使用backtrace???--------測試一下

/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> #include<stdio.h> #include<stdlib.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 *); /* Variables to save original hooks. */ static void *(*old_malloc_hook)(size_t, const void *); static void *(*old_free_hook)(size_t, const void *); extern void *(*malloc_hook)(size_t, const void *); extern void *(*free_hook)(size_t, const void *); /* Obtain a backtrace and print it to @code{stdout}. */ void print_trace (void) { void * array[10]; size_t size; char ** strings; size_t i; size = backtrace(array, 10); strings = backtrace_symbols (array, size); if (NULL == strings) { perror("backtrace_symbols"); exit(EXIT_FAILURE); } printf ("Obtained %zd stack frames--------------start.\n", size); for (i = 0; i < size; i++) printf ("%s\n", strings[i]); printf ("Obtained %zd stack frames-------end.\n", size); free(strings); strings = NULL; } static void my_init (void) { old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; print_trace(); } 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; } main () { my_init (); int *p = malloc(100); p[1] = 23; p[2] = 32; free(p); p = NULL; }
root@test:/home#gcc malloc_hook.c -g -rdynamic -o mallochook // -rdynamic可用來通知鏈接器將所有符號添加到動態符號表中
root@test:/home# ./mallochook malloc (36) returns 0x4b3010 malloc (1182) returns 0x4b3450 malloc (36) returns 0x4b3900 malloc (56) returns 0x4b3930 malloc (360) returns 0x4b3970 malloc (446) returns 0x4b3ae0 Obtained 6 stack frames--------------start. ./mallochook(print_trace+0x2d) [0x401203] ./mallochook(printf_test+0x9) [0x4012d9] ./mallochook() [0x40131c] ./mallochook(main+0xd) [0x401441] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f77f9c4b830] ./mallochook(_start+0x29) [0x401109] Obtained 6 stack frames-------end. freed pointer 0x4b3ae0 malloc (100) returns 0x4b3ae0 freed pointer 0x4b3ae0
貌似可以
比如當前版本有改動 ,和之前的版本對比, 看代碼改動之處。分析代碼是否可能導致內存泄露。。。。。。。
再或者是用valgrind 時 出現了內存分配了,平時不釋放, 但是退出時,會釋放掉。比如mac地址表,每次mac 地址表刪除時, 會分配內存記錄, 但是進程統計后,沒有釋放。但是 使用內存越來越多。
感覺就是內存泄露,但是跑valgrind時, 由於會統一釋放,最后認為跑不出來。
順便回憶一下:valgrind使用見之前文章 https://www.cnblogs.com/codestack/p/10855687.html
常見的內存分配方式分三種:靜態存儲,棧上分配,堆上分配。全局變量屬於靜態存儲,它們是在編譯時就被分配了存儲空間,函數內的局部變量屬於棧上分配,
而最靈活的內存使用方式當屬堆上分配,也叫做內存動態分配了。常用的內存動態分配函數包括:malloc, alloc, realloc, new 等,動態釋放函數包括 free, delete。
Memcheck 工具主要檢查下面的程序錯誤:
• 使用未初始化的內存 (Use of uninitialised memory)
• 使用已經釋放了的內存 (Reading/writing memory after it has been free’d)
• 使用超過 malloc分配的內存空間(Reading/writing off the end of malloc’d blocks)
• 對堆棧的非法訪問 (Reading/writing inappropriate areas on the stack)
• 申請的空間是否有釋放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
• malloc/free/new/delete申請和釋放內存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
• src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)
Valgrind 的局限
Valgrind不檢查靜態分配數組的使用情況。(數組越界 無法檢測出來 即使是在棧空間里面)
全局變量屬於靜態存儲,它們是在編譯時就被分配了存儲空間 檢測不出來;
所以全局數組被才內存一般都是 定義時靠近的變量踩的內存,目前通過這個思路找出來不少踩內存bug
Valgrind占用了更多的內存--可達兩倍於你程序的正常使用量。如果你用Valgrind來檢測使用大量內存的程序就會遇到問題,它可能會用很長的 時間來運行測試