Quelles données de comptabilité un tableau dynamique Delphi contiennent-elles?
-
19-09-2019 - |
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.
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;