概要
WPR/WPA を使用した、アプリのメモリリークの調査方法を紹介します。
解放が行われていないヒープ領域を割り当てたコールスタックがわかり便利です。
内容
WPR/WPA とは?
WPR/WPA は、パフォーマンスのトラブルシューティングに使える強力なツールで、Microsoft よりフリーで公開されています。WPR はWindows Performance Recorder の略で、WPA はWindows Performance Analyzer の略です。
WPR/WPA はWindows SDK に含まれています。
(ダウンロード・インストール方法について特に迷うところはありませんが、具体的な方法につきましては以前のブログにも記載しております。)
WPR/WPA を用いた、アプリのメモリリークの調査方法
以下、二つのセクションに分けて、実際の調査方法を紹介します。
1. WPR を用いてトレース情報収取
2. WPA を用いて、収取したトレース情報の解析
[1. WPR を用いてトレース情報収集]
まずは、メモリリークの発生が疑われるアプリのトレース情報を、以下の方法で収集します。
1.1. ヒープのトレースを有効にするために、トレースの取得したいプロセスに対し、以下のレジストリの設定を行います。
キー | HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<プロセス名> |
名前 | TracingFlags |
種類 | DWORD |
値 | 1 |

1.2. C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\WPRUI.exe を起動します。

1.3. “More options” をクリックします。

1.4. “Heap usage” にチェックを入れ、”Start” をクリックし、情報収集を開始します。

1.5. メモリリークが疑われるアプリを実行します。
1.6. “Save” を押し、情報の収集を終了します。

1.7. “Save” を押すと、”File Name” のパスに、トレース情報が格納されたETLファイルが保存されます。
[2. WPA を用いて、収集したトレース情報の解析]2.1. 上記1.7. で保存したETLファイルをダブルクリックします。すると、WPA が起動します。

2.2. “Trace” → “Load Symbols” を実行し、シンボルをロードします。

2.2. “Memory” の左の三角形をクリックし、”Memory” を展開します。

2.3. 展開された中にある”Heap Allocations” をダブルクリックします。

2.4. すると、右側に”Heap Allocations” の詳細が表示されます。

2.5. アプリ名の右の四角の部分をクリックし、色を有効にします。(下のスクリーンショット参照)
すると、右のグラフに、解放されていないヒープのサイズが時系列で表示されます。
右肩上がりになっていたら、メモリリークの発生が疑われます。

2.6. 詳細を調べるために、表の一番上の列を右クリックし、”Type”と”Stack” の列を追加します。

2.7. わかりやすさのために、”Type” と”Stack” の行ドラッグアンドドロップして、下図の位置に移動します。

2.8. ここで重要になるのは”Type” の”AIFO” です。
AIFO はAllocated Inside Freed Outside の略で、トレース中(= Inside) にヒープが割り当てられ(= Allocated)、トレースの後(= Outside) にフリーされた(= Freed) という意味です。
すなわち、メモリリークの発生が疑われる部分になります。
今回の例を見ると、AIFO が 約42MB あることがわかります。

2.9. “AIFO” を展開し、”Stack” も展開します。
すると、”MyHeapTest.exe!MyAlloc” の関数が、約42M のメモリを割り当てていることがわかります。

2.10. この情報をもとに、ソースコードを確認してみると、この例では、実際にフリーされないコードという事がわかります。
#include "stdafx.h"
#include <Windows.h>
void MyAlloc(){
HANDLE hHeap[3000];
VOID *pHeap;
int i = 0;
//Enter を押すごとに1024000 バイト割り当てる
while (true){
hHeap[i] = HeapCreate(NULL, 0, 0);
pHeap = HeapAlloc(hHeap[i], HEAP_ZERO_MEMORY, 1024000); //1024000 バイト割り当てる
i++;
getchar();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
MyAlloc();
return 0;
}
情報元
・Recording for Heap Analysis (英語)
関連記事
・WPR/WPA を用いた、アプリが何を待っているかを調べる方法
- 2014/05/20(火) 22:11:10|
- ツール
-
| トラックバック:0
-
| コメント:0