Google Heap Profiler


功能及原理

先來大概介紹下Google Heap Profiler,大致有三類功能:

可以分析出在程序的堆內有些什么東西

定位出內存泄露

可以讓我們知道哪些地方分配了比較多的內存

大概的原理就是使用tcmalloc 來代替malloc calloc new等等,這樣Google Heap Profiler就能知道內存的分配情況,從而分析出內存問題。

 

安裝:

一.  安裝與簡介 

(1) 下載源碼包。路徑https://code.google.com/p/google-perftools/

(2) ./configure

(3) make (如果報錯,則./configure --enable-frame-pointers)

(4) make  install

頭文件和庫文件分別在/usr/local/inlcude/google/和/usr/local/lib/下。需要設置環境變量export LD_LIBRARAY_PATH=/usr/local/lib。跟valgrind的profiler工具的不同之處是,Google perftools使用在源程序中插入profiler代碼的方式,而不是valgrind的虛擬機方式,所以Google perftools以庫文件的形式提供了一系列函數接口。為了使用圖形化結果還需要安裝gv,可使用apt-get安裝:sudo apt-get install gv。 

    Google Perftools包括三個工具(注:包括tcmalloc應該是4個),三個工具均支持多線程程序,以下分別介紹。 

 

 

用法

首先需要把tcmalloc鏈接到我們需要分析的程序中, 當然我們也可以動態load 這個lib,但是為了簡單起見,還是推薦大家鏈接這個lib到自己的程序中。

鏈接之后,我們接下來的任務就是得到內存分析的dump文件,我們有兩種方法:

    1.    靜態dump方法:

        直接定義一個環境變量HEAPPROFILE來指定dumpprofile文件的位置,如:/tmp/test.log,它將會在/tmp/目錄下生成很多類似/tmp/test.log.0003.heap文件名的文件

        env HEAPPROFILE="/tmp/test.log" /test/testprog

     2.    動態dump方法:

我們可以調用Google Heap Profiler的API來控制什么時候dump出內存的profiler文件,這樣更加靈活,為此,我們必須包含heap-profiler.h這個頭文件。

HeapProfilerStart() 用來開始內存分析

HeapProfilerStop().  用來終止內存分析

這樣就只會在開始和結束之間產生dump profiler文件。

 

 

如:

#if 1

#include "acconfig.h"

#ifdefHAVE_GPERFTOOLS_HEAP_PROFILER_H

        #include<gperftools/heap-profiler.h>

#else

        #include <google/heap-profiler.h>

#endif

 

#ifdefHAVE_GPERFTOOLS_MALLOC_EXTENSION_H

        #include<gperftools/malloc_extension.h>

#else

        #include<google/malloc_extension.h>

#endif

#include"common/environment.h"

#endif

 

void  heap_profiler_start()

{

 char profile_name[PATH_MAX];

 get_profile_name(profile_name, sizeof(profile_name));

 HeapProfilerStart(profile_name);

}

void  heap_profiler_stop()

{

 HeapProfilerStop();

}

void  heap_profiler_dump(const char *reason)

{

 HeapProfilerDump(reason);

}

bool  heap_profiler_running()

{

 return IsHeapProfilerRunning();

}

void  heap_release_free_memory()

{

 MallocExtension::instance()->ReleaseFreeMemory();

}

void  heap_profiler_stats(char *buf, int length)

{

 MallocExtension::instance()->GetStats(buf, length);

}

 

選項

  •  HEAP_PROFILE_ALLOCATION_INTERVAL

程序內存每增長這一數值之后就dump 一次內存,默認是1G (1073741824)

  •  HEAP_PROFILE_INUSE_INTERVAL

程序如果一次性分配內存超過這個數值dump 默認是100K

 

查看內存dump文件

這么dump文件生成之后,我們接下來就可以查看內存的分布情況,如:

pprof --pdf /test/testProg/tmp/test.log.0001.heap

就是以pdf的形式來顯示這個dump文件,當然我們也可以使用其他的格式來顯示。

  

這就是所有可支持的格式。

注:如果pprof 運行出錯,請檢查時候已經正確安裝,如果出現sh: dot: command not found 這個錯誤,就是需要安裝yum install graphviz -y  

我們也可以專門focus在一些包含某些關鍵字的路徑上,也可以忽略相關的路徑

--focus

--ignore

pprof --pdf --focus=CData /test/testProg/tmp/test.log.0001.heap

使用形式 

需要安裝:graphviz安裝:

graphviz有多種安裝方式,源碼及發行包。

當前最新版源碼下載:

http://120.221.32.79:6510/www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.38.0.tar.gz

 

  pprof的使用形式都是: pprof --option [ --focus=<regexp> ] [ --ignore=<regexp> ] [--line or addresses or functions] 可執行文件路徑  對應的profile路徑。方括號中的項目是可選項目。<regexp>表示正則表達式

 

形如:pprof –gif /root/axw/my_biotest/biotestclient.1940324.profile.0055.heap > graph.gif

 

★options的選項如下:

--text             Generate text report

  --callgrind         Generate callgrindformat to stdout

  --gv               Generate Postscript and display

  --evince           Generate PDF and display

  --web              Generate SVG and display

  --list=<regexp>     Generate source listing ofmatching routines

  --disasm=<regexp>   Generate disassembly of matching routines

  --symbols           Printdemangled symbol names found at given addresses

  --dot              Generate DOT file to stdout

  --ps               Generate Postcript to stdout

  --pdf              Generate PDF to stdout

  --svg              Generate SVG to stdout

  --gif              Generate GIF to stdout

  --raw              Generate symbolized pprof data (useful with remote fetch)

 

★一些宏

HEAP_PROFILE_ALLOCATION_INTERVAL

程序內存每增長這一數值之后就dump 一次內存,默認是1G (1073741824)

         HEAP_PROFILE_INUSE_INTERVAL

程序如果一次性分配內存超過這個數值dump 默認是100K,

字符統計輸出

命令:pprof --text ./RBtree ./RBtree.prof 

關於文本風格輸出結果

序號

說明

1

分析樣本數量(不包含其他函數調用)

2

分析樣本百分比(不包含其他函數調用)

3

目前為止的分析樣本百分比(不包含其他函數調用)

4

分析樣本數量(包含其他函數調用)

5

分析樣本百分比(包含其他函數調用)

6

函數名

 

字符統計結果: 

         501  62.2%  62.2%      714  88.6% RBTree::insert

          84  10.4%  72.6%       84  10.4% RBTree::defaultCmp

          80   9.9%  82.5%      154  19.1% RBTree::nodeCmp

          61   7.6%  90.1%       73   9.1% RBTree::insertFixup

          47   5.8%  95.9%       47   5.8% malloc_trim

           9   1.1%  97.0%      746  92.6% main

           6    0.7%  97.8%        6   0.7% RBTree::rightRotate

           6   0.7%  98.5%        6   0.7% RBTree::leftRotate

           5   0.6%  99.1%        5   0.6% malloc

           3   0.4%  99.5%        3   0.4% operator new

           3   0.4%  99.9%        3   0.4% random_r

           1   0.1% 100.0%        1   0.1% rand

           0   0.0% 100.0%      755  93.7% __libc_start_main 

每行對應一個函數的統計。第一,二列是該函數的本地采樣(不包括被該函數調用的函數中的采樣次數)次數和比例,第三列是該函數本地采樣次數占當前所有已統計函數的采樣次數之和的比例。第四,五列是該函數的累計采樣次數(包括其調用的函數中的采樣次數)和比例。 

 

Text輸出結果分析

14  2.1% 17.2%       58   8.7%std::_Rb_tree::find

含義如下:

14:find函數花費了14個profiling samples

2.1%:find函數花費的profiling samples占總的profilingsamples的比例

17.2%:到find函數為止,已經運行的函數占總的profiling samples的比例

58:find函數加上find函數里的被調用者總共花費的profilingsamples

8.7%:find函數加上find函數里的被調用者總共花費的profilingsamples占總的profiling samples的比例

std::_Rb_tree::find:表示profile的函數

ps: 100samples a second,所以得出的結果除以100,得秒單位

 

 

圖片輸出

命令

Pprof --pdf /root/biotest /var/log/client.1940324.profile.0047> graph.gif  生成的gif統計圖如下。

結果如圖:

 

 

    圖中每個節點對應一個函數,節點中的文字分別為類名,函數明,本地采樣次數比例和累計采樣次數比例(如果跟本地相同則省略)。每條邊表示一個函數調用關系:caller調用callee,邊上的數字表示callee中因為caller調用而被采樣的次數。 

    pprof如果不帶任何選項調用(只有可執行文件路徑和profile文件路徑)則進入互動模式,在互動模式下可使用gv,gif,text等命令來替代前面介紹的帶選項的pprof調用。

比較dump文件

命令:pprof --pdf --base /tmp/test.log.0001.heap /test/testProg/tmp/test.log.0101.heap

 

為了知道在某一段時間內的內存分布情況,或者需要了解某段時間內有沒有內存泄露,我們就需要用到diff我們的dump文件

例如:pprof --pdf --base /tmp/test.log.0001.heap /test/testProg/tmp/test.log.0101.heap

比較了第一個dump文件與第101個文件的差異,而且結果以pdf的形式顯示

Heap Checker 

    堆內存泄漏檢測工具。使用簡單,先在鏈接被檢查程序的時候用-ltcmalloc選項連接Goolge Perftools的堆內存管理庫tcmalloc(tcmalloc會替代C的堆內存管理庫),然后每次用命令行“env HEAPCHECK=normal 可執行程序路徑”來進行檢查,其中檢查形式normal可以替換成其他值,檢查的結果會以屏幕報告的形式給出。以下給出一個實例: 

# cat test_heap_checker.cpp
#include <cstdio>
#include <cstdlib>
int* fun(int n)
{
    int *p1=new int[n];
    int *p2=new int[n];
    return p2;
}
int main()
{
    int n;
    scanf("%d",&n);
    int *p=fun(n);
    delete [] p;
    return 0;
}
# g++ -O0 -g test_heap_checker.cpp -ltcmalloc -o test_heap_checker 

# env HEAPCHECK=normal /home/hongcheng/mycode/google-perftools-tests/test_heap_checker
WARNING: Perftools heap leak checker is active -- Performance may suffer
100
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 400 bytes in 1 objects
The 1 largest leaks:
Leak of 400 bytes in 1 objects allocated from:
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof /home/hongcheng/mycode/google-perftools-tests/test_heap_checker "/tmp/test_heap_checker.13379._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
Exiting with error code (instead of crashing) because of whole-program memory leaks 

    上面的報告顯示有400個字節的內存泄漏,並提示使用pprof進一步跟蹤泄漏來源的方法。 

    包括normal在內總共有4種泄漏檢查方式:minimal,忽略進入main函數之前的初始化過程;normal,報告所有的無法再引用的內存對象;strick,在normal的基礎上增加一些額外的檢查;draconian,在程序退出的時候存在未釋放的內存的情況下報錯。 

    除了前面使用env命令行的全局內存泄漏檢查方式外,還可以作對代碼段的更加細粒度的泄漏檢查。這里需要先在源代碼中包含頭文件google/heap-checker.h。下面是一個檢查代碼段的實例: 

       HeapLeakChecker heap_checker("test_foo");
    {
        code that exercises some foo functionality;
        this code should preserve memory allocation state;
    }
    if (!heap_checker.SameHeap()) assert(NULL == "heap memory leak"); 

  在進入代碼段之前建立當前堆內存使用情況的snapshot,然后在結束代碼段的時候通過與記錄的snapshot對比檢查是否有泄漏。方法NoLeaks()也可以用在這里。下面是一個實例: 

    #include <cstdio>
    #include <cstdlib>
    #include <cassert>
    #include <google/heap-checker.h>
    int* fun(int n)
    {
        int *p2;
        HeapLeakChecker heap_checker("fun");
        {
            new int[n];
            p2=new int[n];
            //delete [] p1;
        }
        assert(!heap_checker.NoLeaks());
        return p2;    
    }
    int main(int argc,char* argv[])
    {
        int n;
        scanf("%d",&n);
        int *p=fun(n);
        delete [] p;
        return 0;
    } 

    注意被檢查程序的main函數形式必須為帶2個參數的形式,否則會在編譯時報告重復定義。運行env命令行將會報告assert失敗。

    另外,還可以跳過某些代碼段的檢查,方式如下: 

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

  <leaky code>處的代碼將被heap-checker忽略。

 

[root@inspur178 my_biotest]# HEAPCHECK=normal ./biotest -w 1/biotest1/ -s 34 -b 4096

WARNING: Perftools heap leakchecker is active -- Performance may suffer

------processID -> 2391436

thread index : 1 -> /1.dat

begin write...

------processID -> 2391436

input command:  end write .

thread [1] complete !

 

c:(null) p:(null)

input command:  quit

c:quit p:(null)

wait join all the thread...

all thread over!!!

Have memory regions w/o callers:might report false leaks

Leak check _main_ detected leaksof 144 bytes in 1 objects

The 1 largest leaks:

Using local file ./biotest.

Leak of 144 bytes in 1 objectsallocated from:

    @7fa290af3d88 icfs_os_setxattr

    @7fa290aef8c9 IcfsContext

    @7fa290aebec5 common_preinit

    @7fa2909207bb icfs_create

    @4037bc main

    @7fa28fa23d1d __libc_start_main

    @4016e9 _start

 

 

If the preceding stack traces arenot enough to find the leaks, try running THIS shell command:

 

pprof ./biotest"/tmp/biotest.2391436._main_-end.heap" --inuse_objects --lines--heapcheck  --edgefraction=1e-10--nodefraction=1e-10 --gv

 

If you are still puzzled aboutwhy the leaks are there, try rerunning this program withHEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or withHEAP_CHECK_MAX_POINTER_OFFSET=-1

If the leak report occurs in asmall fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of fewhundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks morere

Exiting with error code (insteadof crashing) because of whole-program memory leaks

 
 

Google Heap Profiler使用方法

最近在查找內存泄露的問題,使用了一些工具來查找問題,定位問題,但是工具都有各自的優劣,在我們實際的使用過程當中,只有各種工具結合使用才能發揮最大的效用。 由於項目需要,最近也開始使用Google H...
  • jhzhou
  • jhzhou
  • 2012年02月10日 10:12
  • 9922

用google-perftool分析程序的內存/CPU使用

最近,用到了google-perftool分析程序的內存和CPU的使用情況,總結一下使用的一些方法和體會,分享給有需要的朋友。首先,說說google-perftool,它是由google開發的用來分析...
  • zm_21
  • zm_21
  • 2014年06月30日 17:41
  • 1960
 

【揭秘】程序員升職加薪的捷徑來了!

在崗5年,總想着閑下來的時候應該如何安排自己的程序人生呢?無意中看到這個!眼睛亮了..

用google-perftool分析程序的內存/CPU使用

最近,用到了google-perftool分析程序的內存和CPU的使用情況,總結一下使用的一些方法和體會,分享給有需要的朋友。首先,說說google-perftool,它是由google開發的用來分析...

ceph存儲 Google perftools工具內存檢測以及性能分析

一. 安裝與簡介      從主頁http://code.google.com/p/google-perftools/downloads/list下載源碼包,解壓后使用命令序列./configu...
  • skdkjxy
  • skdkjxy
  • 2015年08月04日 09:17
  • 2236

使用ceoh-deploy工具快速部署ceph--先決條件准備

最近按照ceph的官方文檔來部署ceph,發現遇到了不少的問題,其中很多問題都是安裝部署的時候遇到的坑,在這里提出來和大家一起分享探討,如有不足之處歡迎評論。筆者這里使用的操作系統:CentOS7.2...
 

使用ceoh-deploy工具快速部署ceph--部署

最近按照ceph的官方文檔來部署ceph,發現遇到了不少的問題,其中很多問題都是安裝部署的時候遇到的坑,在這里提出來和大家一起分享探討,如有不足之處歡迎評論。存儲集群部署在controllernode...

OpenStack 整合使用Ceph實現(Copy-On-Write)克隆 (筆記)

本文使用的系統環境: CentOS6.5 四台機器 規划如下: HostName IP        安裝服務 c01 192.168.40.101 mon mds osd c02 19...
  • mrz001
  • mrz001
  • 2014年08月28日 14:46
  • 937

如何在ceph中新增google unit test總結

如何在ceph中新增unit test總結

ceph perf counter 源碼分析及使用

ceph perf counter 源碼分析及使用示例1 enum { 2 test_perfcounter_first = 200, 3 test_perfcount...

google開源的C++性能分析工具 - gperftools

gperftools是Google提供的一套工具,其中的一個功能是CPU profiler,用於分析程序性能,找到程序的性能瓶頸。 安裝 gperftools:http://code.google...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM