Что вызывает эту утечку памяти в 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 ответа
Он указывает на линию, в которой была выделена память. И вы правы, удаление строки должно быть обработано компилятором. У вас, вероятно, одна из двух вещей идет не так, как надо.
- Это не единственное, что вы протекаете. Строка принадлежит объекту, который никогда не очищается. Например, CurStruct0Key может быть передан конструктору, где он назначен объекту. Или же
- Вы делаете что-то нехорошее со строкой, например, приводите ее к указателю и обмениваете ее. Не делай этого! Это может нарушить подсчет ссылок!
Проверьте, не является ли любая из этих причин причиной вашей проблемы.
Приобретите лучший инструмент, такой как 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-путь, процедура сработала.
Надеюсь это поможет.