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

是什么导致了Delphi中的内存泄漏?,delphi,delphi-2009,Delphi,Delphi 2009,我就是想不出EurekaLog为我的程序报告的内存泄漏。我使用的是Delphi2009。这是: 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向我指出了第一次分配未释

我就是想不出EurekaLog为我的程序报告的内存泄漏。我使用的是Delphi2009。这是:

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向我指出了第一次分配未释放内存的位置。根据它,我的程序中的行是InputdComFile的第1145行。这条线是:

CurStruct0Key := 'HEAD' + Level0Key;
其中,CurStruct0Key和Level0Key在过程中仅定义为局部变量,在进入和离开过程时,应由Delphi内存管理器动态处理:

var CurStruct0Key, Level0Key: string;
现在我看一下系统单元中的_UStrCat过程。第17572行是:

CALL    _UStrSetLength  // Set length of Dest
我转到系统单元中的_ustresetlength过程,相关行是:

@@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\u ReallocMem”行

那么内存泄漏是什么呢?当然,字符串常量与本地字符串变量的简单连接不应该导致内存泄漏

为什么EurekaLog在Delphi中的一个_ustSetLength例程中将我指向ReallocMem行

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

如有任何帮助或解释,我们将不胜感激


找到的解决方案:

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

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


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

它将您指向相关内存的分配线。您是对的,处理字符串应该由编译器来处理。你可能出了两件事中的一件

  • 这不是你泄漏的唯一东西。字符串属于一个永远不会清理的对象。例如,CurStruct0Key可能会被传递给构造函数,并在其中被分配给对象。或
  • 您正在对字符串执行一些扭曲的操作,例如将其投射到指针并将其传递。别这样!它可以进行参考计数
    检查这些因素是否是问题的原因。

    使用更好的工具,如AQTime,您的“查找内存泄漏”问题将变得更简单。
    一般来说,我会尝试查找所有的类泄漏(TSomething)并忽略字符串类型数据,因为正如上面有人指出的,如果某个泄漏的记录或类类型引用了该字符串,则该字符串不会被释放。整理您的类和记录,字符串泄漏将为您解决。

    我在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路径时,该过程起作用


    希望这有帮助。

    这是报告中唯一的漏洞吗?没有,还有很多其他漏洞。但他们中的大多数人都是这样的,这似乎表明,ReallocMem是一个问题。我举了这个例子,因为我不知道我的代码是如何导致这种情况的。有一种很好的方法可以追踪内存泄漏,而这与你正在做的恰恰相反。不要看你泄露最多的变量类型,而要看你泄露最少的变量类型,因为它很可能拥有你泄露的其他一些东西。首先修复这个漏洞,看看你的内存泄漏列表会变小多少。看来堵漏是一门“艺术”。我得先从静物画开始,然后转向肖像画。不。编程涉及很多艺术,但泄漏跟踪是一门精确的科学。基本规则是,每一块内存应该只有一个所有者(或者是一个数据结构,比如一个对象,或者一个引用计数系统,或者一段代码),并且所有者负责在不再需要时清理它所拥有的所有变量。从这两条规则中,您可以得出一个原则,即只需进行一点分析,就可以尽可能从所有权树的最高层开始谢谢你的这些想法。+1:记住,字符串是引用计数的,所以你的赋值将引用设置为1。每当您传递该字符串时,它只是增加ref。当您的局部变量超出范围时,它会减少refcount。只有当字符串递减为0时,编译器才会释放该字符串。您可以将此字符串传递给类字段、全局变量、记录结构等。任何仍然包含引用的内容都将阻止其被释放。谢谢Mason的回答。昨晚我注意到一个持续运行的应用程序内存无限增长。(续)但终止时没有内存泄漏报告。我一直在重构它,但错过了这个行为开始的时间,所以它可以在任何地方。你的回答让我找到了一行代码,显然是我在一次愚蠢的攻击中添加的。我有几个记录的动态数组,这些记录包含字符串。我将每个数组传递给一个初始化例程,并以某种方式决定在重用它之前对数组进行零填充是明智的。哼!这似乎是我遗漏的一个关键概念。我会调查的。