Question

Voici un programme simple pour vérifier l'allocation de la mémoire. La vérification avant et après les valeurs avec le gestionnaire de tâches suggère que chaque tableau dynamique prend 20 octets de mémoire à la taille = 1. La taille de l'élément est 4, ce qui signifie 16 octets de frais généraux pour les données de comptabilité.

De regarder à travers System.pas, je peux trouver un champ de longueur de tableau à -4 octets, et un nombre de références à -8 octets, mais je n'arrive pas à trouver de références à l'autre 8. Quelqu'un sait ce qu'il fait?

Exemple de programme:

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.
Était-ce utile?

La solution

J'ai également jeté un œil sur System.pas et j'ai remarqué que l'appel GetMem dans _DYNArrayCopyrange prend en charge votre analyse:

Taille allouée = Count * Élément Taille + 2 * Taille (Longint)

. Alors peut-être que les chiffres que vous obtenez du gestionnaire de tâches ne sont pas très précis. Tu pourrais essayer Pointer(someDynArray) := nil et vérifiez la taille de la fuite de mémoire des rapports Fastmm pour les nombres plus fiables.

Éditer: J'ai fait un petit programme de 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.

Cela donne

  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

qui soutient la théorie des frais généraux de 8 octets.

Autres conseils

Les allocations de mémoire ont une granularité pour garantir que toutes les allocations sont alignées. C'est juste la pente causée par cela.

Mis à jour ... Je suis en fait allé vérifier le code (ce que j'aurais dû faire auparavant) et je suis arrivé à la même conclusion que Ulrich, il ne stocke aucune information de type, juste la 2 aérienne longint puis NBElements * ElementSize.
Et, le gestionnaire de tâches n'est pas exact pour ce type de mesure.

Avec la bizarrerie que si vous mesurez la mémoire utilisée par le dynarray, elle augmente non linéairement avec la taille de l'élément: pour un enregistrement avec 2 ou 3 entiers, c'est de la même taille (20), avec 4 ou 5 c'est 28 ... Suivant la granularité des blocs.

Mémoire mesurée avec:

// 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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top