Quali sono i dati di contabilità ha un array dinamico Delphi contiene?
-
19-09-2019 - |
Domanda
Ecco un semplice programma per controllare l'allocazione di memoria. Il controllo prima e dopo valori con Task Manager suggerisce che ogni matrice dinamica occupa 20 byte di memoria a size = 1. La dimensione dell'elemento è 4, il che significa 16 byte di overhead per i dati contabili.
Da guardando attraverso system.pas, posso trovare un campo di lunghezza dell'array a -4 byte, e un conteggio di riferimento a -8 byte, ma io non riesco a trovare alcun riferimento a l'altra 8. Qualcuno sa che cosa fare?
Esempio di programma:
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.
Soluzione
Ho dato un'occhiata in System.pas così e ho notato che la chiamata in GetMem _DynArrayCopyRange sostiene la vostra analyis:
dimensione allocata = count * dimensione dell'elemento + 2 * Sizeof (Longint)
. Quindi forse i numeri si ottiene da task manager, non sono molto precisi. Si potrebbe provare Pointer(someDynArray) := nil
e verificare che il formato perdita di memoria FastMM report per i numeri più affidabili.
Modifica Ho fatto un po 'di programma di test:
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.
Questo produce
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
che sostiene la teoria in testa a 8 byte.
Altri suggerimenti
allocazioni di memoria hanno una granularità per garantire tutte le allocazioni siano allineati. Questa è solo la sbobba causato da questo.
Aggiornamento ...
Io sono andato a controllare il codice (che avrei dovuto fare prima) e sono giunto alla stessa conclusione Ulrich, non è la memorizzazione di tutte le informazioni di tipo, solo l'Longint sovraccarico 2 poi NbElements * ElementSize.
E, Task Manager non è accurata per questo tipo di misura.
Con la singolarità che se si misura la memoria utilizzata dal dynarray, aumenta non linearmente con la dimensione dell'elemento: per un record con 2 o 3 interi è la stessa dimensione (20), con 4 o 5 è 28 ... dopo la granularità delle blocksizes.
Memoria misurata con:
// 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;