2017-10-03 28 views
0

私のアプリケーションでフル・デバッグ・モードでFastMMを使用してメモリー・リークを修正しようとすると、TFormの(子孫の)インスタンスに関するリークが報告されます。チェックしてコードを実行した後、であり、が解放されていないことを確実に確信できます。 Releaseによってスケジュールされた実際の解放が行われる前に、FastMMがリークをチェックしているかのように見えます。Delphiフォームを適切に解放する方法

MyForm: TForm; 
MyForm := TForm.Create(nil); 
... 
MyForm.Release; // FastMM reports MyForm as a leak 

私が代わりにそれらを解放を試みたが、これらのメモリリークは、もはや報告されていませんが、解放時に時々、アクセス違反が発生します。

MyForm: TForm; 
MyForm := TForm.Create(nil); 
... 
MyForm.Free; // // FastMM does not report MyForm as a leak, but sometimes an access violation is triggered 

私はにそれらを解放を試みたが、直後にApplication.ProcessMessagesを呼び出してください。私が理解したように、ZoëPetersonの答えはhttps://stackoverflow.com/a/917187/1465896で読むことができます。それはApplication.ProcessMessagesですぐにいつもクラッシュするので、私は、間違って理解している必要があります:

MyForm: TForm; 
MyForm := TForm.Create(nil); 
... 
MyForm.Release; 
Application.ProcessMessages; // always triggers an access violation 

彼らはメモリリークのログファイルを乱雑に複数のオブジェクトが含まれているので、私は、予想されるメモリリークとして、これらのフォームを登録したくありません、より重要なリークを見つけるのが難しくなります。

私の質問は、Delphiフォームを適切に解放して、FastMMがリークとして報告しないようにする方法です。 (私はプロジェクトを投稿する方法がわからないので、)です。例として含まれるショート、自己、正しい(コンパイル可能ではない)

要求されたよう

は、ここにSSCnCEです:

ファイルFormRelease.dpr:

program FormRelease; 

uses 
    FastMM4 in 'FastMM4.pas', 
    Vcl.Forms, 
    MainForm_fm in 'MainForm_fm.pas' {MainForm}, 
    MyForm_fm in 'MyForm_fm.pas' {MyForm}; 

{$R *.res} 

begin 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TMainForm, MainForm); 
    Application.Run; 
end. 

ファイルMainForm_fm.pas:

unit MainForm_fm; 

interface 

uses 
    Vcl.Forms, 
    MyForm_fm; 

type 
    TMainForm = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 

    private 
    FMyForm: TMyForm; 
    end; 

var 
    MainForm: TMainForm; 

implementation 

{$R *.dfm} 

procedure TMainForm.FormCreate(Sender: TObject); 
begin 
    FMyForm := TMyForm.Create(nil); 
end; 

procedure TMainForm.FormDestroy(Sender: TObject); 
begin 
    FMyForm.Release; 
end; 

end. 

ファイルMyForm_fm.pas:

プログラムを起動し、ALT-F4でそれを停止した後、ファイルFormRelease_MemoryManager_EventLog.txtから

抜粋、:

This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer): 

13 - 20 bytes: TList x 1, Unknown x 1 
21 - 36 bytes: TPen x 1, TMargins x 1, TPadding x 1, TIconImage x 1, TBrush x 2, TTouchManager x 1, TSizeConstraints x 1, UnicodeString x 1, Unknown x 3 
37 - 52 bytes: TGlassFrame x 1, TFont x 2 
53 - 68 bytes: TIcon x 1 
69 - 84 bytes: TControlScrollBar x 2 
101 - 116 bytes: TControlCanvas x 1 
149 - 164 bytes: Unknown x 1 
917 - 1012 bytes: TMyForm x 1 

なぜTMyForm x 1があるFMyForm.Releaseに掲載CM_RELEASEが処理された場合には左?

+1

あなたがリンクした答えは、あなた自身がApplication.ProcessMessagesを呼び出すのを促進しないと思います。それは、リリースが使用されると、結果のメッセージがそこで処理されることを示します。フォームを作成および破棄するために使用するコードを分解できますか?それはどの回答者にとっても重要です。 – nil

+0

Releaseの直後にApplication.ProcessMessagesを呼び出すのは、基本的にFreeを呼び出すのと同じです。延期はありません。リリースは何のためですか。フォーム自体のイベントハンドラでこれを行いますか?それはアクセス違反を説明するでしょう。 – nil

+0

@Nil私はイベントハンドラからではなく、通常のデストラクタから、そして 'finalisation'セクション(私が修正しなければならないアプリケーションはやや独特なアーキテクチャを持っています)からでも行っています。 – Papaya

答えて

1

2つの別々のもののようです。

まず、フォームを明示的に作成しているため、明示的にフォームを解放する必要があります。独自のイベントハンドラの1つからフォーム自体を解放するような特別な場合を除いて、Releaseを呼び出す必要はありません。

MyForm: TForm; 
... 
MyForm := TForm.Create(nil); 
try 
    // Only reference MyForm in this block 
finally 
    MyForm.Free; 
end; 

第2に、Freeを呼び出すことは問題の原因ではありません。私はそれがそれを明らかにすると思います。私が推測しなければならないのは、MyFormまたはそのコンポーネントの1つがこのブロックの外部で参照されているため、アクセス違反が発生していることです。デバッガーを使用してこの参照を見つけて修正します。

+0

合意:私が理解しているように、明示的に 'Release'は、即座ではなく' Free'と全く同じで、イベントハンドラが自分の仕事を解放する前に仕事を終了できるようにします。 – Papaya

+0

問題を引き起こさない無料について、はい、明らかにしているかもしれません。しかし、私が修正することができる時折のクラッシュがある場合、私は決して別のものが存在しないと確信することはできません。 – Papaya

+0

フォームの作成と解放を自分で制御している場合は、そのスコープの外でアクセスされていないことを確認する必要があります。フォームをグローバル変数として扱う場合は、それを宣言してアプリケーションを所有者として割り当て、アプリケーションをシャットダウン時にクリーンアップする必要があります。 –

関連する問題