コアファイル分析からのメモリリークを分析したいと思います。
メモリリークを注入し、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などのコマンドからどのようにアクセスできるのかよくわかりません。シンボル情報をバイナリ形式から変換する方法を誰かに教えてもらえますか?
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などのさまざまな静的および動的ツールで見つけることができます。
プロセスがメモリリークを引き起こしているかどうかをコアダンプを直接調べて特定する方法はないと思います。実際、メモリリークと呼ばれるものはありません。プログラマーがコードを書く意図を知らずに、そのコメントをすることはできません。そうは言っても、コアダンプのサイズを見ればわかります。たとえば、最初の実行後と長時間の実行後に複数のダンプを生成できます。サイズに大きな違いがある場合は、問題が発生している可能性があると推測できます。しかし、繰り返しになりますが、メモリは生産的な目的で使用できます。
メモリリークの実際の分析と追跡には、memtrack、valgrindなどのツールを使用して、mallocとfreeにラッパーを追加し、各allocとfreeに関する追加情報を提供する必要があります。
更新:
16進分析を探していると、次のように表示されます。すべての行は16バイトで、2行で繰り返されます。これは32バイトのチャンクです。 0x4D2は10進数で1234です。だから、あなたのデータはそこにあります。 1つの割り当てチャンクが32バイトである可能性があります。 'new()'ごとにアドレスを16進数でチェックして出力し、比較して32バイトのギャップが観察されているかどうかを確認し、それを説明します。