#記憶體洩漏(Memory Leak)是指程式中已動態分配的堆記憶體因某些原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式運作速度減慢甚至系統崩潰等嚴重後果。
記憶體洩漏並非指內存在物理上的消失,而是應用程式分配某段記憶體後,由於使用錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體未釋放而浪費掉。
#「
#我們在進行程式開發的過程使用動態儲存變數時,不可避免地面對記憶體管理的問題。程式中動態分配的儲存空間,程式執行完畢後需要進行釋放。沒有釋放動態分配的儲存空間而造成記憶體洩漏,是使用動態儲存變數的主要問題。一般情況下,作為開發人員會經常使用系統提供的記憶體管理基本函數,如
malloc、realloc、calloc、free
等,完成動態儲存變數儲存空間的分配和釋放。但是,當開發程式中使用動態儲存變數較多且頻繁使用函數呼叫時,就會經常發生記憶體管理錯誤。」
「
#我們平時開發過程中不可避免的會遇到記憶體洩漏問題,這是常見的問題。既然發生了記憶體洩漏,我們就要排查記憶體洩漏的問題。想必大家也常用到以下排查記憶體問題的工具,如下:
”
「
今天木榮不是介紹上面的排查工具,而是向大家介紹另一個記憶體洩漏排查工具:AddressSanitizer(ASan)。它支援 Linux、OS、Android等多種平台,不只可以偵測記憶體洩漏,它是一個記憶體錯誤偵測工具,可以偵測許多常見的記憶體問題。
」
#常見的記憶體問題偵測:
「
#Address Sanitizer(ASan) 是一個快速的記憶體錯誤偵測工具。它非常快,只拖慢程序兩倍左右(比起Valgrind快多了)。它包括一個編譯器instrumentation模組和一個提供malloc()/free()替代項的執行時間函式庫。從gcc 4.8開始,AddressSanitizer成為gcc的一部分。當然,要獲得更好的體驗,最好使用4.9及以上版本,因為gcc 4.8的AddressSanitizer還不完善,最大的缺點是沒有符號資訊。
」
#使用方法:
gcc -fsanitize=address -o main -g main.c
#include void Fun() { char *pM = malloc(10); } int main(int argc, char *argv[]) { Fun(); return 0; }
編譯輸出
#include #include void Fun() { char *pM = malloc(10); } int main(int argc, char *argv[]) { //Fun(); int *array = malloc(10*sizeof(int)); if(array) { memset(array, 0, 10*sizeof(int)); } int res = array[10]; free(array); return 0; }
運行輸出
ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ gcc -fsanitize=address -o main -g main.c ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ ls main main.c ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ ./main ================================================================= ==3234==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dff8 at pc 0x000000400854 bp 0x7ffccc9253d0 sp 0x7ffccc9253c0 READ of size 4 at 0x60400000dff8 thread T0 #0 0x400853 in main /home/ubuntu/workspace_ex/Linux/ASan/main.c:16 #1 0x7fafc87a883f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) #2 0x4006f8 in _start (/home/ubuntu/workspace_ex/Linux/ASan/main+0x4006f8) 0x60400000dff8 is located 0 bytes to the right of 40-byte region [0x60400000dfd0,0x60400000dff8) allocated by thread T0 here: #0 0x7fafc8bea602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x4007f7 in main /home/ubuntu/workspace_ex/Linux/ASan/main.c:11 #2 0x7fafc87a883f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/workspace_ex/Linux/ASan/main.c:16 main Shadow bytes around the buggy address: 0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00[fa] 0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==3234==ABORTING
#include #include int g_nArray[10] = {0}; void Fun() { char *pM = malloc(10); } int main(int argc, char *argv[]) { //Fun(); /* int *array = malloc(10*sizeof(int)); if(array) { memset(array, 0, 10*sizeof(int)); } int res = array[10]; free(array); */ int nIndex = g_nArray[10]; return 0; }
運行輸出
ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ gcc -fsanitize=address -o main -g main.c ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ ls main main.c ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ ./main ================================================================= ==4196==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000601128 at pc 0x00000040083e bp 0x7ffc8a332540 sp 0x7ffc8a332530 READ of size 4 at 0x000000601128 thread T0 #0 0x40083d in main /home/ubuntu/workspace_ex/Linux/ASan/main.c:26 #1 0x7fda216a583f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) #2 0x400718 in _start (/home/ubuntu/workspace_ex/Linux/ASan/main+0x400718) 0x000000601128 is located 0 bytes to the right of global variable 'g_nArray' defined in 'main.c:4:5' (0x601100) of size 40 SUMMARY: AddressSanitizer: global-buffer-overflow /home/ubuntu/workspace_ex/Linux/ASan/main.c:26 main Shadow bytes around the buggy address: 0x0000800b81d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b81e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b81f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0000800b8220: 00 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 00 00 00 00 0x0000800b8230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800b8270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==4196==ABORTING ubuntu@ubuntu:~/workspace_ex/Linux/ASan$
#include #include #include int g_nArray[10] = {0}; int *p; void Fun() { char *pM = malloc(10); } void Fun1() { int nVar = 0; p = &nVar; } int main(int argc, char *argv[]) { //Fun(); int *array = malloc(10*sizeof(int)); if(array) { memset(array, 0, 10*sizeof(int)); } int res = array[10]; free(array); array[0] = 1; return 0; }
運行輸出
ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ gcc -fsanitize=address -o main -g main.c ubuntu@ubuntu:~/workspace_ex/Linux/ASan$ ./main ================================================================= ==4954==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dff8 at pc 0x000000400b68 bp 0x7ffefbe3b170 sp 0x7ffefbe3b160 READ of size 4 at 0x60400000dff8 thread T0 #0 0x400b67 in main /home/ubuntu/workspace_ex/Linux/ASan/main.c:28 #1 0x7f1bbb78983f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) #2 0x400928 in _start (/home/ubuntu/workspace_ex/Linux/ASan/main+0x400928) 0x60400000dff8 is located 0 bytes to the right of 40-byte region [0x60400000dfd0,0x60400000dff8) allocated by thread T0 here: #0 0x7f1bbbbcb602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602) #1 0x400b0b in main /home/ubuntu/workspace_ex/Linux/ASan/main.c:23 #2 0x7f1bbb78983f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f) SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/workspace_ex/Linux/ASan/main.c:28 main Shadow bytes around the buggy address: 0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00[fa] 0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==4954==ABORTING ubuntu@ubuntu:~/workspace_ex/Linux/ASan$
错误类型 | 错误描述 |
---|---|
(heap) Use after free | 访问堆上已被释放的内存 |
Heap buffer overflow | 堆上缓冲区访问溢出 |
Stack buffer overflow | 栈上缓冲区访问溢出 |
Global buffer overflow | 全局缓冲区访问溢出 |
Use after return | 访问栈上已被释放的内存 |
Use after scope | 栈对象使用超过定义范围 |
Initialization order bugs | 初始化命令错误 |
Memory leaks | 内存泄漏 |
具體可以看 google 的正式文件:https://github.com/google/sanitizers/wiki/AddressSanitizer
#「
#ASan是個很好的偵測記憶體問題的工具,不需要設定環境,使用還方便,編譯時只需要-fsanitize=address -g 就可以, 執行程式時候可以選擇新增對應的ASAN_OPTIONS 環境變數就可以偵測出很多記憶體問題。如果哪裡不清楚可以查看官方說明,歡迎交流學習。
」
以上是Linux下記憶體問題排查利器的詳細內容。更多資訊請關注PHP中文網其他相關文章!