5

最近の投稿で(私のプログラムはメモリを解放しません。なぜですか?)FastMMを使用すると、アプリケーションがシステムに大量のメモリを解放しないことを示します。最近、私は人工的なテストプログラムを作成して、問題がメモリではなく、FastMMでのみ表示されることを確認しました。

このプログラムでは、オブジェクト(前の投稿で使用したものと同じ)を500回作成および破棄します。

メモリ要件は次のとおりです(「プライベートワーキングセット」):

FastMMなし
ループを実行する前:1.2MBループ
を実行した後 :2.1MB

FastMM(アグレッシブデバッグモード)を使用
する場合ループを実行する前:2.1MBループ
を実行した後:25MB

FastMM(リリースモード)
の場合ループを実行する前:1.8MBループ
を実行した後:3MB

ループを数回実行しても、メモリ要件は増加しません。これは、解放されていないメモリが再利用されるため、これがメモリリークではないことを意味します(メモリリークは、実行ごとに数KB / MBのメモリフットプリントを増加させます)。


私の質問は次のとおりです。

FastMMでこの動作を無効にするにはどうすればよいですか?それも可能ですか?FastMMなしまたはFastMMリリースモードを使用してプログラムをリリースすると、適度な量のRAMが「浪費」されることはわかっています。ただし、この動作をオンデマンドで無効にすると、メモリリークを特定するのに役立ちます(私たち?)。実際、私の最初の投稿(リンクを参照)では、多くの人が私にリークがあると示唆しました。混乱は明らかにこの振る舞いのために作成されました。いいえ、漏れがないことは明らかです。大量のメモリを解放することを拒否するのは、メモリマネージャだけです。

余分なメモリを解放しますか?いつ?これを引き起こすものは何ですか?プログラマーはそれをトリガーできますか?たとえば、RAMを大量に消費するタスクを完了し、ユーザーがプログラムをしばらく使用できない(最小化する)可能性があることがわかっている場合、RAMをシステムにフラッシュして戻すことはできますか?ユーザーが私のプログラムの複数のインスタンスを開くとどうなりますか?彼らはRAMをめぐって競争しませんか?

4

4 に答える 4

11

本当に、RAMを「無駄にする」と考えるべきではありません。未使用のRAMを「キャッシュ」するものと考えてください。メモリマネージャは、理由のためにOSに解放するのではなく、未使用のメモリを保持しています。実際、質問でその理由にぶつかりました。

同じ操作をループで再実行し続けるとおっしゃいました。これを行うと、古いメモリがまだ使用可能であり、Windowsに新しいヒープのチャンクを要求する代わりに、すぐに割り当てることができます。これは、「Fast」を「FastMM」に入れるトリックの1つであり、そうでない場合は、プログラムの実行速度が大幅に低下します。

FastMMデバッグモードの図について心配する必要はありません。これはデバッグ専用であり、FullDebugModeに対してコンパイルされたプログラムをリリースする予定はありません。また、「FastMMなし」と「FastMMリリースモードあり」の違いは約1 MBであり、最新のハードウェアでは無視できます。わずか1MBの低コストで、パフォーマンスが大幅に向上します。だから心配しないでください。

于 2010-12-17T23:35:50.557 に答える
9

FastMMを高速化する理由の一部は、メモリの大きなブロックを割り当て、そこから小さな均一なサイズのピースを切り出すことです。ブロックのいずれかの部分が使用中の場合、そのいずれもOSに解放できません。

別のメモリマネージャを使用できます。1つのアプローチは、すべての割り当てをに直接ルーティングすることVirtualAllocです。割り当ては一度にページ全体を占めるように切り上げられるため、小さな割り当てがたくさんあるとプログラムに問題が発生する可能性がありますが、を呼び出すとVirtualFree、メモリがプログラムに属していないことを確信できます。

もう1つのオプションは、すべてをOSヒープにルーティングすることです。を使用しHeapAllocます。プログラムの低フラグメンテーションヒープを有効にすることもできます(Windows Vistaではデフォルトでオンになっています)。これにより、OSはFastMMで使用されるものと同様の戦略を採用しますが、一部のデバッグおよび分析ツールを使用できるようになります。プログラムのメモリ使用量を経時的に追跡するためのMicrosoftから。ただし、を呼び出した後でもHeapFree、一部のメトリックではメモリがプログラムに属していると表示される場合があることに注意してください。

さらに、ワーキングセットとは、現在物理RAMにあるメモリを指します。数値が上がるのを観察したからといって、プログラムがこれ以上メモリを割り当てたことを意味するわけではありません。これは単に、プログラムが以前に割り当てたが、まだRAMに入れられていないメモリに触れたことを意味している可能性があります。ループ中にそのメモリに触れましたが、OSはまだディスクにページアウトすることを決定していません。

于 2010-12-18T01:11:36.887 に答える
3

私はメモリマネージャとして以下を使用します。私がそうするのは、実際にはかなり貧弱なFastMMよりもスレッドの競合の下ではるかに優れたパフォーマンスを発揮するからです。Hoardのようなスケーラブルなマネージャーの方が良いことは知っていますが、これは私のニーズには問題なく機能します。

unit msvcrtMM;

interface

implementation

type
  size_t = Cardinal;

const
  msvcrtDLL = 'msvcrt.dll';

function malloc(Size: size_t): Pointer; cdecl; external msvcrtDLL;
function realloc(P: Pointer; Size: size_t): Pointer; cdecl; external msvcrtDLL;
procedure free(P: Pointer); cdecl; external msvcrtDLL;

function GetMem(Size: Integer): Pointer;
begin
  Result := malloc(size);
end;

function FreeMem(P: Pointer): Integer;
begin
  free(P);
  Result := 0;
end;

function ReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := realloc(P, Size);
end;

function AllocMem(Size: Cardinal): Pointer;
begin
  Result := GetMem(Size);
  if Assigned(Result) then begin
    FillChar(Result^, Size, 0);
  end;
end;

function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean;
begin
  Result := False;
end;

const
  MemoryManager: TMemoryManagerEx = (
    GetMem: GetMem;
    FreeMem: FreeMem;
    ReallocMem: ReallocMem;
    AllocMem: AllocMem;
    RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
    UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
  );

initialization
  SetMemoryManager(MemoryManager);

end.

これはあなたの質問に対する答えではありませんが、コメントに収めるには長すぎるため、このMMに対してアプリを実行するのは興味深いかもしれません。私の推測では、FastMMと同じように機能します。

于 2010-12-18T11:10:34.033 に答える
1

解決済み

Barry Kellyが提案したように、メモリはFastaMMによって自動的に解放されます。これを確認するために、大量のRAMを割り当てた2番目のプログラムを作成しました。WindowsのRAMがなくなるとすぐに、プログラムのメモリ使用率が元の値に戻りました。

問題が解決しました。バリーに感謝します。

于 2010-12-27T16:47:40.573 に答える