为什么TArray<string>没有自动释放?

问题描述 投票:0回答:1
program Project4;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  psAPI,
  Winapi.Windows,
  System.SysUtils;

type
  TSimpleTestClass = class
    buffer: TArray<string>;
  end;
  
  TMatrixTestClass = class
    buffer: TArray<TArray<string>>;
  end;

function CurrentProcessMemory: Cardinal;
var
  MemCounters: TProcessMemoryCounters;
begin
  MemCounters.cb := SizeOf(MemCounters);
  GetProcessMemoryInfo(GetCurrentProcess, @MemCounters, sizeOf(MemCounters));
  OutputDebugString(PChar(MemCounters.WorkingSetSize.ToString()));
end;

function GenerateRandomString(const ALength: Integer; const ACharSequence: String = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'): String;
var
  Ch, SequenceLength: Integer;

begin
  SequenceLength := Length(ACharSequence);
  SetLength(Result, ALength);
  Randomize;

  for Ch := Low(Result) to High(Result) do
    Result[Ch] := ACharSequence.Chars[Random(SequenceLength)];
end;

var
  simpleObj: TSimpleTestClass;
  matrixObj: TMatrixTestClass;
  i: Integer;

begin
  try
    CurrentProcessMemory();
    simpleObj := TSimpleTestClass.Create();
    SetLength(simpleObj.buffer, 10000);
    for i := 0 to 9999 do simpleObj.buffer[i] := GenerateRandomString(32);
    simpleObj.Free();
    CurrentProcessMemory();
  
    matrixObj := TMatrixTestClass.Create();
    SetLength(matrixObj.buffer, 10000);
    for i := 0 to 9999 do begin
      SetLength(matrixObj.buffer[i], 1);
      matrixObj.buffer[i][0] := GenerateRandomString(32);
    end;
    matrixObj.Free();
    CurrentProcessMemory();
    matrixObj := nil; // For breakpoint
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我一直在用上面的代码测试一些东西,似乎类中的 TArray 没有被释放。 这很奇怪,因为据我所知,TArray 和 string 都是引用计数。那么,当我的类的实例为 时,为什么它们没有在这里被释放呢?

编辑:很奇怪的是,第二次运行使用的内存比第一次少得多,我相信那里有一些编译器优化。我尝试使用随机字符串,但没有改变。

delphi
1个回答
0
投票

您正在进行一个错误的假设 - 当您在 Delphi 中释放内存时,它会立即释放回操作系统。事实并非如此。

Delphi 中的内存管理器分配各种大小的块,并且通过从操作系统分配更大的块来在内部处理小分配(我相信内存管理器使用三种不同的块大小,但不要相信我的话)关于这个问题的福音),然后从这个更大的块进行子分配(现在在应用程序中的内存管理器的控制下)。

当您在 Delphi 中释放内存时,它在内部被标记为空闲内存以供以后分配使用,但它仍然由您的程序拥有(从操作系统中可以看出)。

因此,查询进程从操作系统获取了多少内存的函数不会被调整,除非它所属的内部内存块已完全清空,并且 - 我认为 - 是我提到的三个块大小中的大尺寸.

这是为了优化 - 不断分配和释放操作系统内存将对速度产生重大影响,因此内存管理器尝试平衡分配/释放操作系统内存的时间与应用程序的内存消耗。

© www.soinside.com 2019 - 2024. All rights reserved.