web-dev-qa-db-ja.com

コアダンプからのメモリリークを分析する方法

コアファイル分析からのメモリリークを分析したいと思います。

メモリリークを注入し、gcoreコマンドでコアファイルを生成するサンプルコードを作成しました。

#include <stdlib.h>
#include <unistd.h>
void fun()
{
  int *ptr = new int(1234);
}
int main()
{
  int i=0;
  while(i++<2500)
  {
    fun();
}
sleep(360);
return 0;
}

プロセスIDを見つける

ayadav@ajay-PC:~$ ps -aef |grep over  
ajay      8735  6016  0 12:57 pts/2    00:00:00 ./over  
ayadav    8739  4659  0 12:57 pts/10   00:00:00 grep over  

生成されたコア

ayadav@ajay-PC:~$ Sudo gcore 8735
[Sudo] password for ayadav:
0x00007fbb7dda99a0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:81
81      ../sysdeps/unix/syscall-template.S: No such file or directory.
Saved corefile core.8735

私は以下のようにコアファイルから一般的なパターンを見つけました(stackoverflowで提案されているように別のスレッド 生成されたコアファイルだけを見て、プロセスのどの部分がメモリの大部分を使用したかを見つける方法はありますか?

ayadav@ajay-PC:~$ hexdump core.6015 | awk '{printf "%s%s%s%s\n%s%s%s%s\n", $5,$4,$3,$2,$9,$8,$7,$6}' | sort | uniq -c | sort -nr | head
6913 0000000000000000  
2503 0000002100000000  
2501 000004d200000000  
786 0000000000007ffc  
464  
125 1ccbc4d000007ffc  
 92 1ca7ead000000000  
 91 0000000200007ffc  
 89 0000000100007ffc  
 80 0000000100000000  

以下の2つのアドレスは1つが疑われます

2503 0000002100000000  
2501 000004d200000000  

コアファイルには次の繰り返しパターンがあります

0003560 0000 0000 0021 0000 0000 0000 04d2 0000  
0003570 0000 0000 0000 0000 0000 0000 0000 0000  
0003580 0000 0000 0021 0000 0000 0000 04d2 0000  
0003590 0000 0000 0000 0000 0000 0000 0000 0000  
00035a0 0000 0000 0021 0000 0000 0000 04d2 0000  
00035b0 0000 0000 0000 0000 0000 0000 0000 0000  
00035c0 0000 0000 0021 0000 0000 0000 04d2 0000  
00035d0 0000 0000 0000 0000 0000 0000 0000 0000  
00035e0 0000 0000 0021 0000 0000 0000 04d2 0000  
00035f0 0000 0000 0000 0000 0000 0000 0000 0000  
0003600 0000 0000 0021 0000 0000 0000 04d2 0000  
0003610 0000 0000 0000 0000 0000 0000 0000 0000  
0003620 0000 0000 0021 0000 0000 0000 04d2 0000  
0003630 0000 0000 0000 0000 0000 0000 0000 0000  
0003640 0000 0000 0021 0000 0000 0000 04d2 0000

しかし、gdb infoaddressやxなどのコマンドからどのようにアクセスできるのかよくわかりません。シンボル情報をバイナリ形式から変換する方法を誰かに教えてもらえますか?

12
Ajay yadav

1-メモリリークはコアダンプで評価できます。サンプルのc ++の例を取り上げました。

class Base  
{  
public:  
    virtual void fun(){}  
    virtual void xyz(){}  
    virtual void lmv(){}  
    virtual void abc(){}  
};  

class Derived: public Base  
{  
public:  
    void fun(){}  
    void xyz(){}  
    void lmv(){}  
    void abc(){}  
};  

void fun()  
{  
    Base *obj  = new Derived();  
}  
int main()  
{  
    for(int i = 0; i < 2500;i++)
    {
        fun();
    }
    sleep(3600);
    return 0; 
}

2-gcoreコマンドでコアを作成しました

3-コアファイルから繰り返しパターンを検索します。

ayadav@ajay-PC:~$ hexdump core.10639 | awk '{printf "%s%s%s%s\n%s%s%s%s\n", $5,$4,$3,$2,$9,$8,$7,$6}' | sort | uniq -c | sort -nr  | head
   6685 0000000000000000  
   2502 0000002100000000  
   2500 004008d000000000  
    726 0000000000007eff  
    502   
    125 2e4314d000007eff  
     93 006010d000000000  
     81 0000000100007eff  
     80 0000000100000000  
     73 0000000000000001  

0000002100000000および004008d000000000は繰り返されるパターンです

4-各qwordが何であるかを確認しますか?

(gdb) info symbol ...
(gdb) x ...

例:

(gdb) info symbol 0x4008d000
No symbol matches 0x4008d000.
(gdb) info symbol 0x4008d0
vtable for Derived + 16 in section .rodata of /home/ayadav/virtual

5-おそらく最も頻繁なvtableは、メモリリーク、つまり派生vtableに関連している必要があります。

注:コアダンプ分析は、メモリリークを見つけるためのベストプラクティスではないことに同意します。メモリリークは、valgrindなどのさまざまな静的および動的ツールで見つけることができます。

10
Ajay yadav

プロセスがメモリリークを引き起こしているかどうかをコアダンプを直接調べて特定する方法はないと思います。実際、メモリリークと呼ばれるものはありません。プログラマーがコードを書く意図を知らずに、そのコメントをすることはできません。そうは言っても、コアダンプのサイズを見ればわかります。たとえば、最初の実行後と長時間の実行後に複数のダンプを生成できます。サイズに大きな違いがある場合は、問題が発生している可能性があると推測できます。しかし、繰り返しになりますが、メモリは生産的な目的で使用できます。

メモリリークの実際の分析と追跡には、memtrack、valgrindなどのツールを使用して、mallocとfreeにラッパーを追加し、各allocとfreeに関する追加情報を提供する必要があります。

更新:

16進分析を探していると、次のように表示されます。すべての行は16バイトで、2行で繰り返されます。これは32バイトのチャンクです。 0x4D2は10進数で1234です。だから、あなたのデータはそこにあります。 1つの割り当てチャンクが32バイトである可能性があります。 'new()'ごとにアドレスを16進数でチェックして出力し、比較して32バイトのギャップが観察されているかどうかを確認し、それを説明します。

3
joe