<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Linux下內(nèi)存問(wèn)題排查利器

          共 18974字,需瀏覽 38分鐘

           ·

          2023-03-10 23:24


          大家好,今天給大家分享一下Linux下如何排除內(nèi)存泄漏問(wèn)題。工作中,作為一個(gè)程序員,內(nèi)存問(wèn)題是我們經(jīng)常遇到也是容易引起程序崩潰的常見(jiàn)問(wèn)題,嚴(yán)重的后果會(huì)直接導(dǎo)致你的程序宕機(jī)從而帶來(lái)災(zāi)難性的后果。

          1. 內(nèi)存泄漏

          內(nèi)存泄漏(Memory Leak)是指程序中已動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無(wú)法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。

          特點(diǎn)

          • 隱蔽性 因?yàn)閮?nèi)存泄漏的產(chǎn)生原因是內(nèi)存塊未被釋放,屬于遺漏型缺陷而不是過(guò)錯(cuò)型缺陷

          • 積累性 內(nèi)存泄漏通常不會(huì)直接產(chǎn)生可觀察的錯(cuò)誤癥狀,而是逐漸積累,降低系統(tǒng)整體性能,極端的情況下可能使系統(tǒng)崩潰。最直觀的問(wèn)題就是為什么我們的程序開(kāi)始運(yùn)行好好的,過(guò)段時(shí)間就異常退出。

          內(nèi)存泄漏并非指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,由于使用錯(cuò)誤,導(dǎo)致在釋放該段內(nèi)存之前就失去了對(duì)該段內(nèi)存的控制,從而造成了內(nèi)存未釋放而浪費(fèi)掉。

          產(chǎn)生的原因

          我們?cè)谶M(jìn)行程序開(kāi)發(fā)的過(guò)程使用動(dòng)態(tài)存儲(chǔ)變量時(shí),不可避免地面對(duì)內(nèi)存管理的問(wèn)題。程序中動(dòng)態(tài)分配的存儲(chǔ)空間,在程序執(zhí)行完畢后需要進(jìn)行釋放。沒(méi)有釋放動(dòng)態(tài)分配的存儲(chǔ)空間而造成內(nèi)存泄漏,是使用動(dòng)態(tài)存儲(chǔ)變量的主要問(wèn)題。一般情況下,作為開(kāi)發(fā)人員會(huì)經(jīng)常使用系統(tǒng)提供的內(nèi)存管理基本函數(shù),如malloc、realloc、calloc、free等,完成動(dòng)態(tài)存儲(chǔ)變量存儲(chǔ)空間的分配和釋放。但是,當(dāng)開(kāi)發(fā)程序中使用動(dòng)態(tài)存儲(chǔ)變量較多和頻繁使用函數(shù)調(diào)用時(shí),就會(huì)經(jīng)常發(fā)生內(nèi)存管理錯(cuò)誤。

          2. 如何排查內(nèi)存泄漏

          我們平時(shí)開(kāi)發(fā)過(guò)程中不可避免的會(huì)遇到內(nèi)存泄漏問(wèn)題,這是常見(jiàn)的問(wèn)題。既然發(fā)生了內(nèi)存泄漏,我們就要排查內(nèi)存泄漏的問(wèn)題。想必大家也經(jīng)常會(huì)用到以下排查內(nèi)存問(wèn)題的工具,如下:

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

          今天木榮不是介紹上面的排查工具,而是向大家介紹另一個(gè)內(nèi)存泄漏排查工具:AddressSanitizer(ASan)。它支持 Linux、OS、Android等多種平臺(tái),不止可以檢測(cè)內(nèi)存泄漏,它是一個(gè)內(nèi)存錯(cuò)誤檢測(cè)工具,可以檢測(cè)很多常見(jiàn)的內(nèi)存問(wèn)題。

          常見(jiàn)的內(nèi)存問(wèn)題檢測(cè):

          • 內(nèi)存泄漏
          • 越界訪問(wèn)
          • 使用了釋放的內(nèi)存

          3. AddressSanitizer(ASan)工具

          Address Sanitizer(ASan) 是一個(gè)快速的內(nèi)存錯(cuò)誤檢測(cè)工具。它非常快,只拖慢程序兩倍左右(比起Valgrind快多了)。它包括一個(gè)編譯器instrumentation模塊和一個(gè)提供malloc()/free()替代項(xiàng)的運(yùn)行時(shí)庫(kù)。從gcc 4.8開(kāi)始,AddressSanitizer成為gcc的一部分。當(dāng)然,要獲得更好的體驗(yàn),最好使用4.9及以上版本,因?yàn)間cc 4.8的AddressSanitizer還不完善,最大的缺點(diǎn)是沒(méi)有符號(hào)信息。

          使用方法:

          • 用-fsanitize=address選項(xiàng)編譯和鏈接你的程序。
          • 用-fno-omit-frame-pointer編譯,以得到更容易理解stack trace。
          • 可選擇-O1或者更高的優(yōu)化級(jí)別編譯

          gcc -fsanitize=address -o main -g main.c

          內(nèi)存泄漏

          #include <stdlib.h>

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

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

          編譯輸出

          內(nèi)存越界

          • 堆棧內(nèi)存越界
          #include <stdlib.h>
          #include <string.h>

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

          int main(int argc, char *argv[])
          {
              //Fun();
              int *array = malloc(10*sizeof(int));
              if(array)
              {
                      memset(array010*sizeof(int));
              }
              int res = array[10];

              free(array);
              return 0;
          }

          運(yùn)行輸出

          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

          • 全局內(nèi)存越界
          #include <stdlib.h>
          #include <string.h>

          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;
          }

          運(yùn)行輸出

          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$ 

          使用釋放的內(nèi)存

          #include <stdlib.h>
          #include <string.h>
          #include <stdio.h>

          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(array010*sizeof(int));
              }
              int res = array[10];

              free(array);

              array[0] = 1;

              return 0;
          }

          運(yùn)行輸出

          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能檢測(cè)的錯(cuò)誤類(lèi)型

          錯(cuò)誤類(lèi)型錯(cuò)誤描述
          (heap) Use after free訪問(wèn)堆上已被釋放的內(nèi)存
          Heap buffer overflow堆上緩沖區(qū)訪問(wèn)溢出
          Stack buffer overflow棧上緩沖區(qū)訪問(wèn)溢出
          Global buffer overflow全局緩沖區(qū)訪問(wèn)溢出
          Use after return訪問(wèn)棧上已被釋放的內(nèi)存
          Use after scope棧對(duì)象使用超過(guò)定義范圍
          Initialization order bugs初始化命令錯(cuò)誤
          Memory leaks內(nèi)存泄漏
          • 更多細(xì)節(jié)請(qǐng)?jiān)L問(wèn)官網(wǎng)

          具體可以看 google 的官方文檔:https://github.com/google/sanitizers/wiki/AddressSanitizer

          結(jié)束語(yǔ)

          ASan是個(gè)很好的檢測(cè)內(nèi)存問(wèn)題的工具,不需要配置環(huán)境,使用還方便,編譯時(shí)只需要-fsanitize=address -g 就可以, 運(yùn)行程序時(shí)候可以選擇添加對(duì)應(yīng)的 ASAN_OPTIONS 環(huán)境變量就可以檢測(cè)出很多內(nèi)存問(wèn)題。如果哪里不清楚可以查看官方說(shuō)明,歡迎交流學(xué)習(xí)。




          瀏覽 75
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线观看成人av 在线观看亚洲国产 | 久久性爱视频网站 | 18禁片在线网站 | 亚洲精品在线无码观看 | 淫色大吊人妖乱伦视频 |