2011-04-03 19 views
10

私はAllocMem/GetMem/Newルーチンを使ってメモリを割り当て、FreeMem/Disposeルーチンを使ってメモリを解放します。しかし、プロセスエクスプローラでは、プロセスのメモリサイズが縮小されていないことがわかりました。FreeMem/Disposeルーチンを使用してメモリを解放する理由はありますが、メモリは減少しません。

GlobalAllocPtr/HeapAlloc APIとGlobalFreePtr/HeapFree APIを使用すると、メモリサイズが小さくなります。

type 
    TMyRec = record 
    Name: string; 
    TickCount: Cardinal; 
    Buf: array[0..1024 - 1] of byte; 
    end; 
    PMyRec = ^TMyRec; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    FList.Free; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    FList := TList.Create; 
    ReportMemoryLeaksOnShutdown := true; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    i: Integer; 
    Size: Integer; 
    Rec: PMyRec; 
    Heap: Cardinal; 
begin 
    Size := SizeOf(TMyRec); 
    Heap := GetProcessHeap; 
    for I := 0 to 2000 - 1 do 
    begin 
    Rec := AllocMem(Size);        // Delphi routine 
    //GetMem(Rec, Size);        // Delphi routine 
    //New(Rec);           // Delphi routine 

    //Rec := GlobalAllocPtr(GPTR, Size);    // Windows API 
    //Rec := HeapAlloc(Heap, HEAP_ZERO_MEMORY, Size); // Windows API 
    FList.Add(Rec); 
    end; 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    i: Integer; 
    Size: Integer; 
    Rec: PMyRec; 
    Heap: Cardinal; 
begin 
    Size := SizeOf(TMyRec); 
    Heap := GetProcessHeap; 
    for i := FList.Count - 1 downto 0 do 
    begin 
    Rec := PMyRec(FList.Items[i]); 
    FreeMem(Rec, Size);   // Delphi routine 
    //Dispose(Rec);    // Delphi routine 

    //GlobalFreePtr(Rec);   // Windows API 
    //HeapFree(Heap, 0, Rec);  // Windows API 
    end; 
    FList.Clear; 
end; 
+1

これは良い質問(TM)です。コミュニティwikiにする必要があります。 –

答えて

24

これは、デルファイメモリマネージャの仕組みです。それは、それが解放されたすべてのメモリをシステムに戻すのではなく、キャッシュに保持するように、独自のメモリキャッシュをサポートしています。次回は、システム内ではなく、キャッシュ内で要求されたメモリを最初に見つけようとするメモリを割り当てます。そのため、メモリの割り当て/解放が高速になります。

ご存知のように、寿命管理されたフィールド(例のようにex strings)を持つレコードにはFreeMemを使用しないでください。メモリリークが発生します。代わりにDisposeを使用してください。

また、寿命管理されたフィールド(例ではコメント行)を持つレコードに対しては、GetMemを使用しないでください。アクセス違反が発生します。 Newを使用してください。

+5

+1このようなレコードにDispose/Newを使用することについての警告。 –

1

あなたはFreeMemの関数にサイズを指定しないでください。

は、ここに私のテストコードです。パラメータポインタは1つだけです。 そうでなければ、コードはうまく見えます。 私はちょっと疑問に思っています - どうしてあなたはmallocを使用していますか?またはGetMemとFreeMem。

+7

あなたが新しいので、私はこれをdownvoteしませんでしたが、これは本当に有用な答えではありません。あなたはそれを削除する必要がありますので、より多くのdownvotesを取得しないでください。 –

+0

+1 "この回答は役に立ちます" –

11

Windowsからメモリを取得するのは高価な操作なので、デルファイの内蔵メモリマネージャを使用すると、まもなく何か別のメモリが必要になるため、一定量の未使用メモリがキャッシュされます。

多くのメモリを解放すれば、オペレーティングシステムに戻ってくるかもしれませんが、それはまだローカルに残っているので、すぐにはそれ以上のことを求めないでしょう。

+4

少なくともOPはタスクマネージャを使用してメモリを測定していません。ヒープ・マネージャー(fast mm)がヒープ・プールを減らすことを自由に決めるまで、外部ツールに違いは見られません。 –

2

Delphiのメモリマネージャは実際にページごとにメモリを割り当て/解放します。