Delphi动态数组包含哪些簿记数据?

时间:2009-12-14 21:35:24

标签: delphi data-structures overhead dynamic-arrays

这是一个检查内存分配的简单程序。使用任务管理器检查值之前和之后建议每个动态数组在size = 1时占用20个字节的内存。元素大小为4,这意味着16个字节的簿记数据开销。

从查看system.pas,我可以找到一个-4字节的数组长度字段,以及-8字节的引用计数,但我似乎找不到任何对其他的引用8.任何人都知道它们是什么办?

示例程序:

program Project1;

{$APPTYPE CONSOLE}

type
   TDynArray = array of integer;
   TLotsOfArrays = array[1..1000000] of TDynArray;
   PLotsOfArrays = ^TLotsOfArrays;

procedure allocateArrays;
var
   arrays: PLotsOfArrays;
   i: integer;
begin
   new(arrays);
   for I := 1 to 1000000 do
      setLength(arrays^[i], 1);
end;

begin
  readln;
  allocateArrays;
  readln;
end.

3 个答案:

答案 0 :(得分:5)

我也看了一下System.pas,发现_DynArrayCopyRange中的GetMem调用支持你的分析:

  

已分配大小=计数*元素大小   + 2 * Sizeof(Longint)

。因此,从任务管理器获得的数字可能不是很准确。您可以尝试Pointer(someDynArray) := nil并检查FastMM报告的内存泄漏大小,以获得更可靠的数字。

编辑:我做了一个小测试程序:

program DynArrayLeak;

{$APPTYPE CONSOLE}

uses
  SysUtils;

procedure Test;
var
  arr: array of Integer;
  i: Integer;
begin
  for i := 1 to 6 do
  begin
    SetLength(arr, i);
    Pointer(arr) := nil;
  end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  Test;
end.

这会产生

  An unexpected memory leak has occurred. The unexpected small block leaks are:

  1 - 12 bytes: Unknown x 1
  13 - 20 bytes: Unknown x 2
  21 - 28 bytes: Unknown x 2
  29 - 36 bytes: Unknown x 1

支持8字节开销理论。

答案 1 :(得分:2)

内存分配具有粒度以确保所有分配都已对齐。这只是由此造成的污点。

答案 2 :(得分:0)

...更新 我实际上去检查代码(我之前应该做的)并且我得出了与Ulrich相同的结论,它不存储任何类型信息,只是2 Longint开销然后是NbElements * ElementSize。
并且,任务管理器对于这种措施并不准确。

奇怪的是,如果你测量dynarray使用的内存,它会随着元素的大小非线性增加:对于一个有2或3个整数的记录,它的大小相同(20),有4或5,它是28 ...遵循块大小的粒度。

记忆测量:

// Return the total Memory used as reported by the Memory Manager
function MemoryUsed: Cardinal;
var
  MemMgrState: TMemoryManagerState;
  SmallBlockState: TSmallBlockTypeState;
begin
  GetMemoryManagerState(MemMgrState);
  Result := MemMgrState.TotalAllocatedMediumBlockSize + MemMgrState.TotalAllocatedLargeBlockSize;
  for SmallBlockState in MemMgrState.SmallBlockTypeStates do begin
      Result := Result + SmallBlockState.UseableBlockSize * SmallBlockState.AllocatedBlockCount;
  end;
end;