这是一个检查内存分配的简单程序。使用任务管理器检查值之前和之后建议每个动态数组在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.
答案 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;