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.
È stato utile?

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top