Delphi中导致内存泄漏的原因是什么?

时间:2009-12-29 22:32:41

标签: delphi delphi-2009

我无法弄清楚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指向我首先分配未释放内存的位置。根据它,我的程序中的行是InputGedcomFile的第1145行。那条线是:

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将我指向属于Delphi的_UStrSetLength例程中的ReallocMem行?

这是Delphi 2009,我正在使用新的unicode字符串。

我们非常感谢您的帮助或解释。


找到解决方案:

该字符串被分配给新菜单项的属性。菜单项已添加到菜单中。然后新的菜单项被释放,因此我认为一切都被清理干净了。因为字符串(通过引用计数)仍然被使用,因为它被复制到项目中,所以字符串不会在内存中释放,即使它是作为例程中的局部变量引入的。

通常这不应该是泄漏。但是,我的程序有时会删除各种菜单项“menu.item.delete(i)”。我没有意识到删除不会释放项目本身的内存。因此,引用计数的字符串没有被释放,从而导致泄漏。

解决方案是将我的“menu.item.delete(i)”语句更改为:“menu.item [i] .free”。

3 个答案:

答案 0 :(得分:12)

它指向您分配有问题内存的行。你是对的,处理字符串应该由编译器处理。你可能会遇到两件事之一。

  1. 这不是你唯一泄漏的东西。该字符串属于一个永远不会被清理的对象。例如,CurStruct0Key可能会传递给构造函数,在构造函数中,CurStruct0Key会被赋值给一个对象。或
  2. 你正在做一些与字符串混淆的事情,例如将它转换为指针并将其传递。不要这样做!它可以参考计数!
  3. 检查这些是否是导致问题的原因。

答案 1 :(得分:6)

获得更好的工具,如AQTime,您的“发现内存泄漏”问题将变得更加简单。 一般情况下,我尝试查找所有类泄漏(TSomething)并忽略String类型数据,因为正如上面指出的那样,如果某个泄漏的记录或类类型引用该字符串,则不会释放该字符串。整理你的类和你的记录,字符串泄漏都将为你修复。

答案 2 :(得分:0)

我在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路径时,程序有效。

希望这有帮助。