1. 程式人生 > >【linux】Valgrind工具集詳解(十二):DHAT:動態堆分析器

【linux】Valgrind工具集詳解(十二):DHAT:動態堆分析器

一、概述

DHAT動態堆分析器。Massif(堆分析器)是在程式結束後輸出分析結果,而DHAT是實時輸出結果,所以叫做動態堆分析器。Massif只記錄堆記憶體的申請和釋放,DHAT還會分析堆空間的使用率、使用週期等資訊。
DHAT的功能:它首先記錄在堆上分配的塊,通過分析每次記憶體訪問時所指定的塊判斷是否是之前已經記錄過的塊,並收集統計這些資訊,最終輸入如下結果:

  1. 總共分配的堆記憶體數(位元組數和塊數);
  2. 程式執行中堆記憶體的最大數(位元組數和塊數);
  3. 塊平均壽命(從分配到釋放之間的指令數);
  4. 塊中每個位元組的平均讀寫次數(“訪問率”);
  5. 對於總是僅分配一個大小的塊的分配點,該大小為4096位元組或更少:計數表示訪問塊內每個位元組偏移的頻率。

使用這些統計資訊可以得出以下結果:

  1. 潛在的洩漏(程序生命週期內):由該點分配的塊只是累積,並且僅在執行結束時釋放;
  2. 過度浪費記憶體(英文原文excessive turnover):由該點分配的塊只是累積,吞噬很多堆記憶體,但會釋放,不會保持很長時間;
  3. 過度瞬態記憶體:從分配到釋放的時間非常短;
  4. 無用或未充分利用的記憶體:已分配但未完全使用的記憶體,或只寫到記憶體中但隨後並沒有讀的記憶體;
  5. 使用效率低的塊

二、使用

1、例子原始碼
#include <stdio.h>
#include <stdlib.h>
int main() { char *x = (char *)malloc(100000); int *i = (int*) malloc(sizeof(int)); int *arr[1000]; for(*i=0; *i<1000; ++(*i)) { arr[*i] = (int*)malloc(sizeof(int)); *arr[*i] = *i; } int *j = (int*) malloc(sizeof(int)); for(*i=0; *i<1000; ++(*i)) { (*j) += *arr[*i]; free(arr[*i]); } int
*arr1[1000]; for(*i=0; *i<1000; ++(*i)) { arr1[*i] = (int*)malloc(sizeof(int)); *arr1[*i] = *i; } for(*i=0; *i<1000; ++(*i)) { free(arr1[*i]); } free(i); free(j); free(x); return 0; }
2、編譯
gcc -g main.c
3、分析

執行命令:valgrind --tool=exp-dhat ./a.out
輸出結果如下:

$ valgrind --tool=exp-dhat ./a.out
==14000== DHAT, a dynamic heap analysis tool
==14000== NOTE: This is an Experimental-Class Valgrind Tool
==14000== Copyright (C) 2010-2013, and GNU GPL'd, by Mozilla Inc
==14000== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==14000== Command: ./a.out
==14000== 
==14000== 
==14000== ======== SUMMARY STATISTICS ========
==14000== 
==14000== guest_insns:  333,340
==14000== 
==14000== max_live:     104,008 in 1,003 blocks
==14000== 
==14000== tot_alloc:    108,008 in 2,003 blocks
==14000== 
==14000== insns per allocated byte: 3
==14000== 
==14000== 
==14000== ======== ORDERED BY decreasing "max-bytes-live": top 10 allocators ========
==14000== 
==14000== -------------------- 1 of 10 --------------------
==14000== max-live:    100,000 in 1 blocks
==14000== tot-alloc:   100,000 in 1 blocks (avg size 100000.00)
==14000== deaths:      1, at avg age 209,049 (62.71% of prog lifetime)
==14000== acc-ratios:  0.00 rd, 0.00 wr  (0 b-read, 0 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x400592: main (main.c:6)
==14000== 
==14000== -------------------- 2 of 10 --------------------
==14000== max-live:    4,000 in 1,000 blocks
==14000== tot-alloc:   4,000 in 1,000 blocks (avg size 4.00)
==14000== deaths:      1,000, at avg age 55,405 (16.62% of prog lifetime)
==14000== acc-ratios:  1.00 rd, 1.00 wr  (4,000 b-read, 4,000 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x4005CC: main (main.c:12)
==14000== 
==14000== Aggregated access counts by offset:
==14000== 
==14000== [   0]  2000 2000 2000 2000 
==14000== 
==14000== -------------------- 3 of 10 --------------------
==14000== max-live:    4,000 in 1,000 blocks
==14000== tot-alloc:   4,000 in 1,000 blocks (avg size 4.00)
==14000== deaths:      1,000, at avg age 49,514 (14.85% of prog lifetime)
==14000== acc-ratios:  0.00 rd, 1.00 wr  (0 b-read, 4,000 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x4006C8: main (main.c:25)
==14000== 
==14000== Aggregated access counts by offset:
==14000== 
==14000== [   0]  1000 1000 1000 1000 
==14000== 
==14000== -------------------- 4 of 10 --------------------
==14000== max-live:    4 in 1 blocks
==14000== tot-alloc:   4 in 1 blocks (avg size 4.00)
==14000== deaths:      1, at avg age 208,950 (62.68% of prog lifetime)
==14000== acc-ratios:  17004.00 rd, 4004.00 wr  (68,016 b-read, 16,016 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x4005A3: main (main.c:8)
==14000== 
==14000== Aggregated access counts by offset:
==14000== 
==14000== [   0]  21008 21008 21008 21008 
==14000== 
==14000== -------------------- 5 of 10 --------------------
==14000== max-live:    4 in 1 blocks
==14000== tot-alloc:   4 in 1 blocks (avg size 4.00)
==14000== deaths:      1, at avg age 153,940 (46.18% of prog lifetime)
==14000== acc-ratios:  1000.00 rd, 1000.00 wr  (4,000 b-read, 4,000 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x400627: main (main.c:15)
==14000== 
==14000== Aggregated access counts by offset:
==14000== 
==14000== [   0]  2000 2000 2000 2000 
==14000== 
==14000== 
==14000== 
==14000== ==============================================================
==14000== 
==14000== Some hints: (see --help for command line option details):
==14000== 
==14000== * summary stats for whole program are at the top of this output
==14000== 
==14000== * --show-top-n=  controls how many alloc points are shown.
==14000==                  You probably want to set it much higher than
==14000==                  the default value (10)
==14000== 
==14000== * --sort-by=     specifies the sort key for output.
==14000==                  See --help for details.
==14000== 
==14000== * Each allocation stack, by default 12 frames, counts as
==14000==   a separate alloc point.  This causes the data to be spread out
==14000==   over far too many alloc points.  I strongly suggest using
==14000==   --num-callers=4 or some such, to reduce the spreading.
==14000== 

三、結果分析

1、概要資訊
==14000== ======== SUMMARY STATISTICS ========
==14000== guest_insns:  333,340
==14000== max_live:     104,008 in 1,003 blocks
==14000== tot_alloc:    108,008 in 2,003 blocks
==14000== insns per allocated byte: 3

guest_insns:程式執行的指令總數;
max_live:程式執行期間堆記憶體最大值;
tot_alloc:程式執行期間堆記憶體累計值;
insns per allocated byte:平均每到每條指令分配的堆記憶體數

2、每次分配的堆記憶體的資訊

如果程式很大,分配堆記憶體的點很多,一般會不列出點的資訊,DHAT會按照分配記憶體的數量由多到少的順序列出前n個,n預設是10,可以由選項–show-top-n=來設定,一般情況下會設定幾百個。
下面是其中一個堆記憶體分配點的的詳細資訊:

==14000== ======== ORDERED BY decreasing "max-bytes-live": top 10 allocators ========
==14000== -------------------- 1 of 10 --------------------
==14000== max-live:    100,000 in 1 blocks
==14000== tot-alloc:   100,000 in 1 blocks (avg size 100000.00)
==14000== deaths:      1, at avg age 209,049 (62.71% of prog lifetime)
==14000== acc-ratios:  0.00 rd, 0.00 wr  (0 b-read, 0 b-written)
==14000==    at 0x4C28EF0: malloc (vg_replace_malloc.c:296)
==14000==    by 0x400592: main (main.c:6)
==14000== 

max-live:程式執行期間堆記憶體最大值
tot-alloc:程式執行期間堆記憶體累計值
deaths:釋放次數
acc-ratios:分配的塊中的每個位元組平均讀寫次數

四、命令列選項

–show-top-n= [default: 10]
設定顯示的條目,預設是10,這個值比較小,一般情況下至少要設定為幾百。

–sort-by= [default: max-bytes-live]
在執行結束時,DHAT根據某個指標對累積的分配點進行排序,並顯示最高得分條目。 --sort-by 選擇用於排序的指標:

  1. max-bytes-live 程式執行期間堆記憶體最大值,按位元組計算[預設];
  2. tot-bytes-allocd 程式執行期間堆記憶體累計值,按位元組計算;
  3. max-blocks-live 程式執行期間堆記憶體最大值,按塊計算;
  4. tot-blocks-allocd 程式執行期間堆記憶體累計值,按塊計算

友情提示:

  1. 按max-blocks-live排序往往會顯示建立大量小物件的分配點。
  2. –num-callers = 4或更小,更容易的分析分配點。