Я пытаюсь найти и исправить утечку памяти, которая присутствует в моем приложении. Инструмент анализа памяти, который я пробую — C ++ Memory Validator — показывает, что примерно 1 310 706 байт выделяется примерно каждые 5 минут. Стек вызовов для этих распределений прослеживается до того, что я считаю диспетчером памяти Embarcadero, написанным на паскале. Рассматриваемая функция:
{Allocates a new sequential feed medium block pool and immediately splits off a
block of the requested size. The block size must be a multiple of 16 and
medium blocks must be locked.}
function AllocNewSequentialFeedMediumPool(AFirstBlockSize: Cardinal): Pointer;
var
LOldFirstMediumBlockPool: PMediumBlockPoolHeader;
LNewPool: Pointer;
begin
{Bin the current sequential feed remainder}
BinMediumSequentialFeedRemainder;
{Allocate a new sequential feed block pool}
LNewPool := VirtualAlloc(nil, MediumBlockPoolSize, MEM_COMMIT, PAGE_READWRITE);
if LNewPool <> nil then
begin
{Insert this block pool into the list of block pools}
LOldFirstMediumBlockPool := MediumBlockPoolsCircularList.NextMediumBlockPoolHeader;
PMediumBlockPoolHeader(LNewPool).PreviousMediumBlockPoolHeader := @MediumBlockPoolsCircularList;
MediumBlockPoolsCircularList.NextMediumBlockPoolHeader := LNewPool;
PMediumBlockPoolHeader(LNewPool).NextMediumBlockPoolHeader := LOldFirstMediumBlockPool;
LOldFirstMediumBlockPool.PreviousMediumBlockPoolHeader := LNewPool;
{Store the sequential feed pool trailer}
PNativeUInt(PByte(LNewPool) + MediumBlockPoolSize - BlockHeaderSize)^ := IsMediumBlockFlag;
{Get the number of bytes still available}
MediumSequentialFeedBytesLeft := (MediumBlockPoolSize - MediumBlockPoolHeaderSize) - AFirstBlockSize;
{Get the result}
Result := Pointer(PByte(LNewPool) + MediumBlockPoolSize - AFirstBlockSize);
LastSequentiallyFedMediumBlock := Result;
{Store the block header}
PNativeUInt(PByte(Result) - BlockHeaderSize)^ := AFirstBlockSize or IsMediumBlockFlag;
end
else
begin
{Out of memory}
MediumSequentialFeedBytesLeft := 0;
Result := nil;
end;
end;
Обратите внимание, что переменная MediumBlockPoolSize является константой, которая является точным размером утечки.
Я думаю, что происходит, когда мое приложение теряет память, наступает момент, когда оно выделяет что-то, и в этот момент мы запрашиваем новый блок памяти (1,3 МБ) из пула доступной памяти, и я думаю, что это происходит примерно каждый раз. 5 минут Однако, это не говорит мне точно, откуда течет утечка. Есть ли способ, как я могу лучше определить источник утечки?
Я просмотрел код и убедился, что все новости удаляются, а указатели не переназначаются без предварительного удаления и т. Д.
Ниже приведено дерево вызовов, когда выделен блок памяти. Обратите внимание, что если я закомментирую это дерево вызовов в коде, блок появится в другом месте в моем коде, и так далее, и так далее.
Благодарю.
Delphi / C ++ Builder RTL использует (уменьшенную версию) Менеджер памяти FastMM по умолчанию. FastMM выделяет память в сегментах и использует освобожденную память для будущих распределений, а не возвращает ее обратно в ОС. Память не возвращается в ОС, пока приложение не завершится.
Это не настоящая утечка, но ваш Validator этого не знает, поскольку не знает, как диспетчер памяти RTL на самом деле использует выделенную память во время выполнения (по этой же причине вы не можете использовать диспетчер задач Windows для диагностики утечек).
Если вы хотите отслеживать реальный утечки, установите полную версию FastMM и используйте собственный встроенный детектор утечки. Только фактический менеджер памяти, используемый во время выполнения, знает, как используется память, и может точно знать, что является настоящей утечкой или нет.
Других решений пока нет …