Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク 
[掲載 2006年01月08日] [更新 2017年04月20日] Delphi 一般・その他
メモリマネージャー FastMM の導入
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro + FastMM498
[整理番号 - 0580]







FastMM とは


Delphi 2006 のメモリマネージャの作者でもある Pierre le Riche 氏が開発した、Delphi と BCB (Borland C++ Builder) 用のメモリマネージャです。

アプリケーションでメモリを使用する場合、連続した領域が確保できず、メモリの断片化という現象が発生します。特に、オブジェクトの生成、解放を多く繰返すとこの現象は顕著となります。最悪の場合「メモリ不足」などで処理が中断されることもあります。FastMM はこの問題を改良するためのメモリマネージャーです。
.NET ではガベージコレクションという、断片化したメモリを調整して有効に使用する機能があらかじめ備わっています。

本ページでは基本的な使用方法だけ説明しています。詳しい使用方法は以下のリンクの記事、あるいは、FastMM 添付のデモプログラムを参考にしてください。




[備考]
メモリリークの検出も含めて、総合的なデバッグを考えているのであれば、EurekaLog 等のツール類の利用も検討する価値があるかも知れません。




01_インストールの手順


Delphi 4 以上、または BCB 5 以上で使用可能です。
Delphi に最新のアップデートを導入しておきます。FastMM4 は下記の sourceforge .net のダウンロードのページから入手できます。

解凍後のファイル構成は、下図のようになっています。


図1
解凍後のファイル構成

  • [CPP Builder Support] は C++Builder 用
  • [Demos] は使用例
  • [FullDebugMode DLL] はフルデバッグ用の DLL
  • [Replacement BorlndMM DLL] もフルデバッグ用の DLL
  • [Translations] は各国対応バージョン
    日本語対応はないので筆者の場合関係なし

FastMM4 を使用するには、下図の選択中のファイルを、パスの通ったフォルダにコピーします。これでインストール完了です。


図2
パスの通ったフォルダにコピー
  • FastMM498 直下にある 以下の 3 つのファイルをライブラリのパスが通ったフォルダにコピーする
    FastMM4.pas
    FastMM4Messages.pas
    FastMM4Options.inc




02_基本的な使用方法


次のコードのように、プロジェクトのソースコードの uses の先頭に追加するだけです。


リスト1 
テストに使用したプロジェクトのソースコード
program Project1;

uses
  FastMM4,  //これを追加
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


実際にテストに使用したコードです。


リスト2 
テスト用のユニットのコード
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    SL : TStringList;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  TStringListは、使い終わったら解放しなければならない
//  このプログラムでは解放していないので、メモリリークが発生する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  SL := TStringList.Create;
end;

end.


このプログラムをコンパイルして実行し、Button1 をクリックした後、終了します。すると、下図のよなかダイアログが表示され、メモリリークが発生していることが分かります。


  • 図3
  • TStringList でメモリリークが発生しているのがわかる
  • EXE の単独実行時は、このダイアログは表示されない




03_フルデバッグの方法


上の例では、TStringList が原因でメモリリークが発生しているこが分かりますが、どの TStringList が原因となっているかまでは分かりません。
フルデバッグを利用すると、どの TStringList が解放されていないかを知ることができます。

以下は、フルデバッグの行うための手順です。





03-01_フルデバッグに必要な DLL をシステムフォルダにコピー


フルデバッグには、[インストールの手順] で説明したファイルの他に、フルデバッグ用の DLL が必要です。これは下図の場所にある FastMM_FullDebugMode.dll です。この DLL をシステム的にバスの通った場所にコピーします。
今回限りであれば EXE が生成されるフォルダでいいのですが、別のプロジェクトでも使用することを考えてシステムフォルダにコピーしました。筆者の場合、64 ビット版の Windows です。したがって、[Windows] [SysWOW64] フォルダにコピーしました。

FastMM_FullDebugMode64.dll は、64 ビット版の DLL です。64 ビット版のプロジェクトをフルデバッグする場合は、ファイル名の 64 の部分を削除して、FastMM_FullDebugMode.dll とします。それをシステムフォルダにコピーします。



図4
必要な DLL




03-02_プロジェクトオプションのデバッグ情報を設定


[プロジェクト] [オプション] の、以下のデバッグ情報 を True にします。これ以外はデフォルトの状態と仮定しています。コンパイラの [デバッグ情報] はデフォルト値は True です。[リンク] [デバッグ情報] のデフォルト値は False です。
  • [Delphi コンパイラ] [コンパイル] のデバッグ情報
  • [Delphi コンパイラ] [リンク] または [リンカ] のデバッグ情報


図5
図6




03-03_プロジェクトのソースコードに FastMM4 を追加して実行


以上で準備終了です。
[基本的な使用方法] と同じく、プロジェクトのソースコードに FastMM4 を追加します。
今回のテストコードは、その下の図のようにしています。


リスト3 
フルデバッグのテストに使用したプロジェクトのソースコード
program Project1;

uses
  FastMM4,   //これを追加
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


  • 図7
  • フルデバッグのテスト用のコード (注意 : これは画像)

[再構築] あるは [ビルド] して、実行します。Button2 をクリックした後、プログラムを終了すると、以下のダイアログが表示されます。


  • 図8
  • TStringList でメモリリークが発生しているのがわかる
  • EXE の単独実行時は、このダイアログは表示されない

下図のように、ログファイルが出力されます。
EXE を直接実行した場合は、ログファイルへの出力はありません。


図9
フルデバッグで出力されるログファイル

出力されたログファイルの内容は次のようになっています。行番号 40 で生成した TStringList が解放されていないことが分かります。メモリリークがなければこのログは出力されません。






03-04_XXX_MemoryManager_EventLog.txt が出力されない場合


メモリリークがあるのにログファイルが出力されない場合は、プロジェクトを [ビルド] または [再構築] してみてください。プロジェクトのオプションを変更すると、ビルドあるいは再構築しないと変更が有効とならないことがあります。

また、[デバッガを使わずに実行] ([Shift] + [Ctrl] + [F9]) ボタンで実行すると、メモリリークは検出できません。[実行] ボタン、または [F9] でコンパイルして実行します。

FastMM4Options.inc ファイルの以下のオプションの無効、有効もチェックしてみてください。これらのオプションが無効になっていたら有効にします。オプションの定義は、各々オプションについて1カ所 (1 行) だけです。

  • FullDebugMode
  • LogMemoryLeakDetailToFile
  • ClearLogFileOnStartup
変更したら、プロジェクトを [ビルド] または [再構築] します。
ClearLogFileOnStartup は必ずしも必要ではありませんが、このオプションを有効にすると、ログ作成時に前のログを削除してから新規にログが作成されるようになります。


リスト4 
FastMM4Options.inc ファイルのオプションの定義が無効になっている場合がある
{. の . (ドット) を削除すれば有効となる。逆に . を追加すれば無効となる
{.$define FullDebugMode}

    . 削除する

{$define FullDebugMode}


[備考 1]
FastMM4 では FastMM4Options.inc ファイルでオプションを設定する方式となっています。各々のオプションについては FastMM4Options.inc ファイル内に詳しい説明があります。ただし英文です。
日本語に翻訳して読みたい場合、ファイルをウェブブラウザで表示して、ブラウザのアドオン等の翻訳機能を利用するという手もあります。


[備考 2]
デバッグのトレースで FastMM4.pas をトレースしないようにするには、FastMM4.pas の interface 部の先頭に {$D-} を追加します。





04_Delphi 付属の FastMM を利用する場合 ( Delphi 2006 以降 )


Delphi 2006 からはメモリマネージャとして FastMM (サブセット版) が含まれています。これを使用したテスト結果です。


リスト5 
テストに使用したプロジェクトのソースコード
テスト用のユニットのコードは、[基本的な使用方法] の項のコードと同じ
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  ReportMemoryLeaksOnShutdown := True;  //これを追加

  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


テストプログラムを実行し、Button1 をクリックした後、プログラムを終了すると、以下のダイアログが表示されます。EXE を単独で実行した場合も同じダイアログとなります。


  • 図10
  • TStringList でメモリリークが発生しているのがわかる