首頁  >  文章  >  系統教程  >  Linux下記憶體問題排查利器

Linux下記憶體問題排查利器

王林
王林轉載
2024-02-12 22:20:141049瀏覽

1. 記憶體洩漏

#記憶體洩漏(Memory Leak)是指程式中已動態分配的堆記憶體因某些原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式運作速度減慢甚至系統崩潰等嚴重後果。

Linux下記憶體問題排查利器

#特點

  • 隱藏性 因為記憶體洩漏的產生原因是記憶體區塊未被釋放,屬於遺漏型缺陷而不是過錯型缺陷
  • # 積累性 記憶體洩漏通常不會直接產生可觀察的錯誤症狀,而是逐漸積累,降低系統整體效能,極端的情況下可能使系統崩潰。最直觀的問題就是為什麼我們的程式開始運作正常,過段時間就異常退出。

記憶體洩漏並非指內存在物理上的消失,而是應用程式分配某段記憶體後,由於使用錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體未釋放而浪費掉。

產生的原因

#「

#我們在進行程式開發的過程使用動態儲存變數時,不可避免地面對記憶體管理的問題。程式中動態分配的儲存空間,程式執行完畢後需要進行釋放。沒有釋放動態分配的儲存空間而造成記憶體洩漏,是使用動態儲存變數的主要問題。一般情況下,作為開發人員會經常使用系統提供的記憶體管理基本函數,如malloc、realloc、calloc、free等,完成動態儲存變數儲存空間的分配和釋放。但是,當開發程式中使用動態儲存變數較多且頻繁使用函數呼叫時,就會經常發生記憶體管理錯誤。

#2. 如何排查記憶體洩漏

#我們平時開發過程中不可避免的會遇到記憶體洩漏問題,這是常見的問題。既然發生了記憶體洩漏,我們就要排查記憶體洩漏的問題。想必大家也常用到以下排查記憶體問題的工具,如下:

  • memwatch
  • # mtrace
  • # dmalloc
  • # ccmalloc
  • valgrind
  • debug_new

今天木榮不是介紹上面的排查工具,而是向大家介紹另一個記憶體洩漏排查工具:AddressSanitizer(ASan)。它支援 Linux、OS、Android等多種平台,不只可以偵測記憶體洩漏,它是一個記憶體錯誤偵測工具,可以偵測許多常見的記憶體問題。

#常見的記憶體問題偵測:

  • 記憶體洩漏
  • 越界訪問
  • 使用了釋放的記憶體

3. AddressSanitizer(ASan)工具

#Address Sanitizer(ASan) 是一個快速的記憶體錯誤偵測工具。它非常快,只拖慢程序兩倍左右(比起Valgrind快多了)。它包括一個編譯器instrumentation模組和一個提供malloc()/free()替代項的執行時間函式庫。從gcc 4.8開始,AddressSanitizer成為gcc的一部分。當然,要獲得更好的體驗,最好使用4.9及以上版本,因為gcc 4.8的AddressSanitizer還不完善,最大的缺點是沒有符號資訊。

#使用方法:

  • 用-fsanitize=address選項編譯並連結你的程式。
  • 用-fno-omit-frame-pointer編譯,以得到更容易理解stack trace。
  • 可選擇-O1或更高的最佳化等級編譯
gcc -fsanitize=address -o main -g main.c

記憶體洩漏

#include 

void Fun()
{
    char *pM = malloc(10);
}

int main(int argc, char *argv[])
{
    Fun();
    return 0;
}

編譯輸出

Linux下記憶體問題排查利器

記憶體越界

  • 堆疊記憶體越界
#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$

AddressSanitizer能检测的错误类型

错误类型 错误描述
(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中文網其他相關文章!

陳述:
本文轉載於:lxlinux.net。如有侵權,請聯絡admin@php.cn刪除