gperftools使用

近期嘗試使用gperftools對C++內存泄露進行排查,所以對gperftools進行了一些瞭解。gperftools是google用來進行程序性能優化的工具集合,主要包括tcmalloc和profiler兩個庫。其可以提供如下的功能:

  1. tcmalloc:與glibc中的malloc函數相比,tcmalloc的內存分配效率要遠高於malloc,可以提高高併發的性能 ,降低系統的負載
  2. cpu profiler:對程序中各個函數使用的CPU情況進行監控探測
  3. heap checker:對程序是否發生內存泄露進行檢測
  4. heap profiler:對程序中申請的內存區域進行監控

heap checker

使用

對於使用heap checker的使用,需要注意的是一般是對整個程序進行檢測,要求這個程序會自動退出,而不是那種會不停的運行的服務。其實gperftools的官方文檔中說當發現內存泄露的同時會通過exit()使程序退出並打印相關的內存信息。

In this case, the heap-checker starts tracking memory allocations before the start of main(), and checks again at program-exit. If it finds any memory leaks – that is, any memory not pointed to by objects that are still “live” at program-exit – it aborts the program (via exit(1)) and prints a message describing how to track down the memory leak (using pprof).

對於heap checker的使用有兩種方法:

  1. 設置LD_PRELOAD 來預加載tcmalloc庫,然後執行相關的運行命令,例如:

        LD_PRELOAD=/usr/lib64/libtcmalloc.so
        HEAPCHECK=normal ./example1
    
  2. 在編譯時使用靜態庫進行連接,然後執行相關的運行命令,例如:

        g++ -g -o example1 example1.cpp -ltcmalloc
        HEAPCHECK=normal ./example1
    

對於可以退出並且發生內存泄露的程序,其輸出結果如下:

這裏寫圖片描述

對於發生內存泄露但是一直不能夠退出的程序,其輸出結果如下:

這裏寫圖片描述

檢查模式

可以注意到對於第二行命令中前幾個字段HEAPCHECK=normal,可以理解爲設置進行內存檢查時的檢查類型(或者檢查的嚴格程度)。一共有以下幾種檢查的方式:

  1. minimal:忽略在進入main()函數之前的所有內存分配
  2. normal:檢查在程序運行時的所有內存分配的情況,報告在程序結束時沒有釋放的內存。在google中最常用的模式就是這種模式。
  3. strict:與normal類似,但是也報告在全局析構中忘記析構導致發生的內存泄露
  4. draconian:屬於一種更精確的內存檢查,如果申請的沒存沒有被釋放,他就會報告內存泄露
  5. local:使用這個模式可以實現只檢查程序中的指定部分的代碼是否發生內存泄露。可以檢測開始的地方創建 HeapLeakChecker對象,然後在檢測結束的地方調用NoLeaks(),例如:

    HeapLeakChecker heap_checker("test_foo");
      {
        //code that exercises some foo functionality;
        //this code should not leak memory;
      }
      if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");
    
  6. as-is:利用這個模式再加上一些環境變量的設置,可以進行更靈活的檢查

官方文檔是這樣寫的:

“Minimal” heap-checking starts as late as possible in a
initialization, meaning you can leak some memory in your
initialization routines (that run before main(), say), and not trigger
a leak message. If you frequently (and purposefully) leak data in
one-time global initializers, “minimal” mode is useful for you.
Otherwise, you should avoid it for stricter modes.

“Normal” heap-checking tracks live objects and reports a leak for any
data that is not reachable via a live object when the program exits.

“Strict” heap-checking is much like “normal” but has a few extra
checks that memory isn’t lost in global destructors. In particular, if
you have a global variable that allocates memory during program
execution, and then “forgets” about the memory in the global
destructor (say, by setting the pointer to it to NULL) without freeing
it, that will prompt a leak message in “strict” mode, though not in
“normal” mode.

“Draconian” heap-checking is appropriate for those who like to be very
precise about their memory management, and want the heap-checker to
help them enforce it. In “draconian” mode, the heap-checker does not
do “live object” checking at all, so it reports a leak unless all
allocated memory is freed before program exit. (However, you can use
IgnoreObject() to re-enable liveness-checking on an object-by-object
basis.)

“Normal” mode, as the name implies, is the one used most often at
Google. It’s appropriate for everyday heap-checking use.

跳過某些代碼的檢查

既然前面已經提到了可以設置檢查程序的部分代碼,對於那些已經知道會放生內存泄露後者發生內存泄露但是可以接受的代碼,同樣也可以設置不進行檢查,例如:

...
   {
     HeapLeakChecker::Disabler disabler;
     <leaky code>
   }
...

除了上述的方法,還有一種方法就是使用IgnoreObject() 在此函數中傳入需要忽略檢測的對象的指針,可以使用UnIgnoreObject()取消這個忽略。

環境變量

  1. HEAP_PROFILE_ALLOCATION_INTERVAL:上文說每當一定量的內存被新申請分配出來時,就會輸出profile文件,這個變量值就是控制多少字節,默認是(1024*1024*1024)1GB,粒度相對比較大,可以調整爲幾百MB甚至更小。
  2. HEAP_PROFILE_MMAP:有時候程序申請內存的方式是通過mmap,sbrk系統調用而不是malloc free,如果想profile這些內存,可以開啓這個變量,默認是false。我們工程代碼中就有些調用了mmap申請大塊內存的地方,開啓這個環境變量,能更準確跟蹤內存走向。
  3. HEAP_PROFILE_MMAP_ONLY:如其名,只profile mmap,sbrk申請的內存。

heap profiler

heap profiler也是使用tcmalloc庫,通過heap profiler可以不斷的生成相應的profile文件。對於那些運行一段時間就會退出的程序,一般會生成一個XXXXX-end.heap的文件可以使用pprof命令以及相關的參數(–text或者–pdf)進行查看;但是,對於那些正常情況下的永遠運行不會停止的服務,使用heap profiler可以根據生成的XXXX.heap文件跟蹤程序的內存使用情況,也可以使用pprof命令進行查看。

使用

heap profiler的使用與heap checker的使用方法差不多,也是有兩種方式:

  1. 設置LD_PRELOAD 來預加載tcmalloc庫,然後執行相關的運行命令,例如:

    LD_PRELOAD=/usr/lib64/libtcmalloc.so
    HEAPPROFILE=/tmp/example1 ./example1
    
  2. 在編譯時使用靜態庫進行連接,然後執行相關的運行命令,例如:

    g++ -g -o example1 example1.cpp -ltcmalloc
    HEAPPROFILE=/tmp/example1 ./example1
    

其中HEAPPROFILE 環境變量是用來設置生成的dump文件的前綴的,其運行結果如下:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章