为什么我释放内存后程序的内存使用率没有恢复正常?

时间:2010-12-15 08:43:28

标签: delphi delphi-2007

考虑下一个示例应用程序

program TestMemory;


{$APPTYPE CONSOLE}

uses
  PsAPI,
  Windows,
  SysUtils;

function GetUsedMemoryFastMem: cardinal;
var
    st: TMemoryManagerState;
    sb: TSmallBlockTypeState;
begin
    GetMemoryManagerState(st);
    result := st.TotalAllocatedMediumBlockSize + st.TotalAllocatedLargeBlockSize;
    for sb in st.SmallBlockTypeStates do
    begin
        result := result + sb.UseableBlockSize * sb.AllocatedBlockCount;
    end;
end;

function GetUsedMemoryWindows: longint;
var
  ProcessMemoryCounters: TProcessMemoryCounters;
begin
  Result:=0;
  ProcessMemoryCounters.cb := SizeOf(TProcessMemoryCounters);
  if GetProcessMemoryInfo(GetCurrentProcess(), @ProcessMemoryCounters, ProcessMemoryCounters.cb) then
   Result:= ProcessMemoryCounters.WorkingSetSize
  else
   RaiseLastOSError;
end;

procedure Test;
const
  Size = 1024*1024;
var
  P : Pointer;
begin
  GetMem(P,Size);

      Writeln('Inside');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');

  FreeMem(P);
end;

begin
      Writeln('Before');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');

      Test;

      Writeln('After');
      Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem));
      Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows));
      Writeln('');
      Readln;
end.

应用返回的结果是

Before
FastMem 1.844
Windows 3.633.152

Inside
FastMem 1.050.612
Windows 3.637.248

After
FastMem 2.036
Windows 3.633.152

我想知道为什么BeforeAfter的内存使用结果不同:

3 个答案:

答案 0 :(得分:11)

任何内存管理器(包括FastMM)都会产生一些开销,否则Delphi可能只是使用了Windows内存管理。

您观察到的差异是开销:

  • FastMM用于跟踪内存使用情况的结构,
  • 内存,FastMM尚未返回Windows内存管理,以便在将来优化类似的内存分配。

答案 1 :(得分:2)

因为内存管理器在后台做了一些聪明的事情来加速性能。

答案 2 :(得分:0)

getmem / malloc / free是如何工作的?

堆分配器 - 由malloc使用...

1)在内部分配大块(通常为64K到1兆字节)的内存,然后将块进行细分,以便在程序中为您提供100byte和200byte的对象和字符串。 当你释放内存时,所有发生的事情都是从内部缓冲区中分配它的地方,或者块被标记为空闲。没有实际发生!

2)因此,您可以将HEAP视为大块内存的列表,并且程序中的所有对象只是这些块的一小部分。

3)内存中的大块内存只有在释放内部的所有对象时才被释放,所以通常的情况是,当你释放一些对象时,除了一些比特被标记为可用之外没有任何实际发生的事情。

这是对堆系统的一个相当天真的描述,但是大多数堆以类似的方式工作,但是做了更多的优化。但是你的问题是为什么内存不会下降而答案是因为实际上没有任何内容被释放。保留内存页面以便下次调用“new”或“malloc”等...

图片

内部堆积是一块100Kb的巨大块

You call "malloc(1000)" or "getmem(1000)" to get a 1K block of memory.

然后发生的一切都是1K内存块来自100kb内存块,在该块中有99K内存可用。如果你继续调用malloc或getmem那么它将继续将较大的块分开,直到它需要另一个更大的块。

通过调用malloc或getmem分配的每个小内存块实际上会获得大约16或24个额外字节(取决于分配器)的额外内存。该内存是分配器用来知道分配内容以及分配位置的位。