Que dados de contabilidade uma matriz dinâmica Delphi contém?
-
19-09-2019 - |
Pergunta
Aqui está um programa simples para verificar a alocação de memória. Verificar os valores antes e depois do gerenciador de tarefas sugere que cada matriz dinâmica ocupa 20 bytes de memória no tamanho = 1. O tamanho do elemento é 4, o que significa 16 bytes de sobrecarga para dados de contabilidade.
Ao procurar através do System.PAS, posso encontrar um campo de comprimento de matriz em -4 bytes e uma contagem de referência em -8 bytes, mas não consigo encontrar nenhuma referência ao outro 8. Alguém sabe o que faz?
Programa de amostra:
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.
Solução
Também dei uma olhada no System.Pas e notei que a chamada getMem em _dyNarraycoPyRange suporta sua análise:
Tamanho alocado = contagem * Tamanho do elemento + 2 * tamanho de (longint)
. Então, talvez os números que você obtém do gerente de tarefas não sejam muito precisos. Você poderia tentar Pointer(someDynArray) := nil
e verifique quais relatórios do FastMM de tamanho de vazamento de memória para números mais confiáveis.
Editar: Eu fiz um pequeno programa de teste:
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.
Isso rende
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
que suporta a teoria das 8 bytes de 8 bytes.
Outras dicas
As alocações de memória têm granularidade para garantir que todas as alocações estejam alinhadas. Esta é apenas a inclinação causada por isso.
Atualizado ... Na verdade, fui verificar o código (o que eu deveria ter feito antes) e cheguei à mesma conclusão que a Ulrich, ele não está armazenando nenhuma informação de tipo, apenas as duas sobrecargas de longint e depois nBelEments*elementize.
E o gerente de tarefas não é preciso para esse tipo de medida.
Com a estranheza de que, se você medir a memória usada pelo Dynarray, aumenta não linearmente com o tamanho do elemento: para um registro com 2 ou 3 números inteiros, é do mesmo tamanho (20), com 4 ou 5 é 28 ... Após a granularidade dos bloqueios.
Memória medida com:
// 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;