Что вызывает эту утечку памяти в Delphi?

Я просто не могу понять эту утечку памяти, о которой EurekaLog сообщает для моей программы. Я использую Delphi 2009. Вот оно:

Memory Leak: Type=Data; Total size=26; Count=1;
The stack is:
System.pas  _UStrSetLength  17477
System.pas  _UStrCat           17572
Process.pas  InputGedcomFile  1145

Это все, что есть в стеке. EurekaLog указывает мне на место, где память, которая не была освобождена, была впервые выделена. Согласно этому, строка в моей программе - это строка 1145 InputGedcomFile. Эта строка:

CurStruct0Key := 'HEAD' + Level0Key;

где CurStruct0Key и Level0Key просто определены в процедуре как локальные переменные, которые должны динамически обрабатываться диспетчером памяти Delphi при входе и выходе из процедуры:

var CurStruct0Key, Level0Key: string;

Итак, теперь я смотрю на процедуру _UStrCat в системном блоке. Строка 17572 это:

CALL    _UStrSetLength  // Set length of Dest

и я иду к процедуре _UStrSetLength в системном блоке, и соответствующие строки:

@@isUnicode:
        CMP     [EAX-skew].StrRec.refCnt,1 // !!! MT safety
        JNE     @@copyString  // not unique, so copy

        SUB     EAX,rOff      // Offset EAX "S" to start of memory block
        ADD     EDX,EDX       // Double length to get size
        JO      @@overflow
        ADD     EDX,rOff+2    // Add string rec size
        JO      @@overflow
        PUSH    EAX           // Put S on stack
        MOV     EAX,ESP       // to pass by reference
        CALL    _ReallocMem
        POP     EAX
        ADD     EAX,rOff      // Readjust
        MOV     [EBX],EAX     // Store
        MOV     [EAX-skew].StrRec.length,ESI
        MOV     WORD PTR [EAX+ESI*2],0 // Null terminate
        TEST    EDI,EDI       // Was a temp created?
        JZ      @@exit
        PUSH    EDI
        MOV     EAX,ESP
        CALL    _LStrClr
        POP     EDI
        JMP     @@exit

где строка 17477 - это строка "CALL _ReallocMem".

Итак, что же такое утечка памяти? Конечно, простая конкатенация строковой константы с локальной строковой переменной не должна вызывать утечку памяти.

Почему EurekaLog указывает мне на строку ReallocMem в процедуре _UStrSetLength, которая является частью Delphi?

Это Delphi 2009, и я использую новые строки Unicode.

Любая помощь или объяснение здесь будет высоко ценится.


Решение найдено:

Строка присваивалась атрибуту нового пункта меню. Элемент меню был добавлен в меню. Тогда новый пункт меню был освобожден, и, таким образом, я думал, что все было убрано. Поскольку строка (посредством подсчета ссылок) все еще использовалась, потому что она была скопирована в элемент, строка не была освобождена в памяти, даже если она была введена в качестве локальной переменной в подпрограмме.

Обычно это не должно быть утечка. Тем не менее, моя программа иногда удаляет различные пункты меню с помощью "menu.item.delete(i)". Что я не понял, так это то, что удаление не освобождает память самого элемента. Поэтому эта строка с подсчетом ссылок не освобождается, что приводит к утечке.

Решением было изменить мои выражения "menu.item.delete (i)" на: "menu.item[i].free".

3 ответа

Решение

Он указывает на линию, в которой была выделена память. И вы правы, удаление строки должно быть обработано компилятором. У вас, вероятно, одна из двух вещей идет не так, как надо.

  1. Это не единственное, что вы протекаете. Строка принадлежит объекту, который никогда не очищается. Например, CurStruct0Key может быть передан конструктору, где он назначен объекту. Или же
  2. Вы делаете что-то нехорошее со строкой, например, приводите ее к указателю и обмениваете ее. Не делай этого! Это может нарушить подсчет ссылок!

Проверьте, не является ли любая из этих причин причиной вашей проблемы.

Приобретите лучший инструмент, такой как AQTime, и ваши проблемы с "поиском утечки памяти" станут проще. В общем, я пытаюсь найти все утечки классов (TSomething) и игнорировать данные типа String, потому что, как указывалось выше, строка не освобождается, если на нее ссылается какая-то утечка записи или тип класса. Разберитесь с вашими классами и вашими записями, и утечки строк будут исправлены для вас.

Я испытывал утечку памяти в моем проекте Delphi. Эта процедура прекрасно работала на моей машине, но была выполнена на машинах, подключенных к сети.

procedure accTrimWorkingSet;
var
 hProcess: THandle;
begin
 hProcess:=OpenProcess(PROCESS_SET_QUOTA, false, GetCurrentProcessId);
 try
   SetProcessWorkingSetSize(hProcess, $FFFFFFFF, $FFFFFFFF);
 finally CloseHandle(hProcess); end;
end;

Оказалось, что я использую картированное погружение. Когда я перешел на UNC-путь, процедура сработала.

Надеюсь это поможет.

Другие вопросы по тегам