メモリリーク
メモリリークの検出(Delphi5~2005)
Delphi5から2005までは、MemCheckでメモリリークを検出できた。
使い方は以下の通り。
- MemCheckをプロジェクトに組み込む。
- プロジェクトソースにMemChkの呼び出しを追加。
begin
MemChk;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
- プロジェクトオプションの「コンパイラ」で、「スタックフレームの生成」をチェック
- プロジェクトオプションの「リンカ」で、「TD32デバッグ情報を含める」をチェック
メモリーリークが起こるとファイルに詳細な情報が保存される。
メモリリークの検出(Delphi2006~)
Delphi2006以降はメモリマネージャが変わったため、MemCheckは使えなくなった。その代わり、標準でメモリリーク検出機能が用意されている。
使い方は以下の通り。
begin
ReportMemoryLeaksOnShutdown := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
ただ、この機能はメモリリークが起こったことを知らせるだけで、どこでメモリリークが起こったかはわからない。
詳細な情報がほしければ、FastMMを使うのがいい。新しいメモリマネージャはFastMMのサブセットで、どうせならフルセットを使ったほうがいい。
FastMMでメモリリークを検出する手順は以下の通り。
- FastMMに含まれるFastMM_FullDebugMode.dllを、プロジェクトのEXEファイルのある場所にコピー。またはDLLが検索されるフォルダ(例えば、C:\Windows\System32など)にコピー。
- プロジェクトソースを開く
- usesの先頭にFastMM4を追加。
- プロジェクトオプション - ディレクトリ/条件 - 条件定義に以下を追加。
FullDebugMode;LogMemoryLeakDetailToFile;ClearLogFileOnStartup;EnableMemoryLeakReporting
- 「プロジェクト - オプション - コンパイラ - スタックフレームの生成」をチェック。
- 「プロジェクト - オプション - リンカ - TD32デバッグ情報を含める」をチェック。
- プロジェクトを再構築。
- メモリリークが見つかるとアプリケーション終了時にダイアログが出る。
- メモリリークの詳細は、EXEと同じフォルダに"EXEファイル名_MemoryManager_EventLog.txt"というファイルができているのでそれを見る。
見つけるのに苦労したメモリリークの原因
- Indyを使うとメモリリークが起こるが、これは気にしないでよさそう。
- Newで確保したポインタを、型を指定せずにDisposeする。
- TList, TObjectListのClearをoverrideしたのにもかかわらず、inheritedしていない。
- ListViewを仮想モードで使ったとき、Addでアイテムを追加するとメモリリークを起こす。
本来、使い方が間違っているのだが、どうしてもこれを使う必要があった。そのため、Addで得たポインタを適当なTListに保存しておいて、必要なくなったらまとめて破棄するようにした。