Welche Buchhaltungsdaten enthält ein Delphi Dynamic Array?
-
19-09-2019 - |
Frage
Hier ist ein einfaches Programm zur Überprüfung der Speicherzuweisung. Das Überprüfen vor und nach den Werten mit Task Manager schlägt vor, dass jedes dynamische Array 20 Bytes Speicher bei Größe = 1. Die Elementgröße beträgt 4, was 16 Bytes Overhead für Buchhaltungsdaten bedeutet.
Von system.pas kann ich ein Arraylängefeld in -4 Bytes und eine Referenzzahl bei -8 Bytes finden, aber ich kann anscheinend keine Hinweise auf die anderen 8 finden. Hat jemand, was er tut?
Beispielprogramm:
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.
Lösung
Ich habe auch ein Blick auf System.pas geworfen und festgestellt, dass der GetMem -Anruf in _dynarrayCopyrange Ihre Analyis unterstützt:
zugewiesene Größe = Anzahl * Elementgröße + 2 * Größe (Longint)
. Vielleicht sind die Zahlen, die Sie vom Task -Manager erhalten, nicht sehr genau. Du könntest es versuchen Pointer(someDynArray) := nil
und prüfen Sie, welche Speicherleckgröße Fastmm -Berichte für zuverlässigere Zahlen berichtet.
Bearbeiten: Ich habe ein kleines Testprogramm gemacht:
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.
Dies ergibt
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
Das unterstützt die 8 -Byte -Overwadtheorie.
Andere Tipps
Speicherzuweisungen haben Granularität, um sicherzustellen, dass alle Zuteilungen ausgerichtet sind. Dies ist nur der dadurch verursachte Slop.
Aktualisiert ... Ich habe den Code (den ich schon einmal hätte tun sollen) und bin zu dem gleichen Schluss wie Ulrich gekommen. Es speichert keine Informationen, nur den 2 Longint -Overhead, dann die Elemente.
Und Task Manager ist für diese Art von Maß nicht korrekt.
Mit der Kuriosität, dass, wenn Sie das von der Dynarray verwendete Speicher messen, nicht linear mit der Größe des Elements erhöht: Für einen Datensatz mit 2 oder 3 Ganzzahlen ist es die gleiche Größe (20), mit 4 oder 5 ist es 28 ... folgt der Granularität des Blocks.
Speicher gemessen mit:
// 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;