为什么使用FreeMem/Dispose例程来释放内存,但没有减少内存?

10

我使用 AllocMem/GetMem/New 程序来分配内存,然后使用 FreeMem/Dispose 程序来释放内存。但是我发现(通过进程资源管理器)进程的内存大小没有减小。

如果我使用 GlobalAllocPtr/HeapAlloc 和 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)。应该是社区维基。 - Clóvis Valadares Junior
4个回答

24

这就是 Delphi 内存管理器的工作原理 - 它支持自己的内存缓存,以避免将每个已释放的内存都返回给系统,而是将其保存在缓存中。下一次分配内存时,它会首先尝试在缓存中查找所请求的内存,而不是在系统中查找。这使得内存分配/释放更快。

顺便说一句,永远不要对具有受管生命周期字段的记录(例如字符串,就像您的示例中一样)使用 FreeMem - 这会导致内存泄漏。请改用 Dispose

此外,永远不要为具有受管生命周期字段的记录(您示例中的注释行)使用 GetMem - 这会导致访问冲突。请改用 New


11

出现这种情况是因为从Windows获取内存是一项昂贵的操作,所以当您使用Delphi内置的内存管理器时,它会缓存一定量的未使用内存,因为您很可能很快需要它来做其他事情。

如果您释放了大量内存,您可能会看到它将一些内存归还给操作系统,但它仍然保留一些本地内存,以便不必立即请求更多内存。


4
至少 OP 没有使用任务管理器来测量内存。正如 Mason 所说,除非你释放了足够的内存,堆管理器(fast mm)才会决定减少其堆池,否则在任何外部工具中都看不到差异。 - Warren P

2
Delphi的内存管理器实际上是按页分配/释放内存的。

1
你不应该在FreeMem函数中指定Size参数,因为它只需要一个参数 - 指针。 除此之外,你的代码看起来很好。 我只是想知道 - 为什么你要使用malloc和free而不是new和delete / dispose?或者是GetMem和FreeMem。

7
我没有因为你是新手而给这个回答投反对票,但这并不是一个有用的回答,因为它没有回答被问的问题。你应该删除它,这样你就不会得到更多的反对票了。 - Mason Wheeler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接