我试图了解Delphi服务器应用程序中的内存问题:最初我怀疑彻底泄漏,但是现在相信,由于编译器在使用+动态连接字符串时使用了隐藏的临时文件,因此内存的闲置时间比应有的更长。 ,造成痛苦的自由空间内存碎片。
这是Windows上的一整套32位服务器应用程序,Delphi版本已经很老了,我认为它是7,但可以肯定是Unicode之前的版本,并使用Nexus 3内存管理器在其中编写了DLL来挂接所有分配/ free调用(以及GB的内存跟踪)。
我有应用程序源代码,但没有编译器;我不是该应用程序的开发人员(甚至不是Delphi开发人员),但创建了广泛的自定义工具来监视,跟踪和分析内存。我一直在IDA Pro反汇编程序中选择.EXE。
我试图将这种情况减少到最低限度。此代码无意于编译:
procedure TaskThread.RunWorkLoop
begin
while not Terminated do
begin
tsk := WaitForWorkToDo(); // this could sit for minutes at a time
SetThreadName('Working on ' + tsk.Name);
tsk.Run(); // THIS COULD TAKE A LONG TIME
SetThreadName('Idle');
end
end;
Run Code Online (Sandbox Code Playgroud)
SetThreadName() 接受一个const字符串参数并将其挂起,以便系统的其他部分知道此线程在做什么。
我对代码的反汇编显示,编译器已分配了一个隐藏的本地临时变量,以接收“工作中”部分和任务名称部分的串联,这是传递给的SetThreadName地方,它还保留了字符串的句柄。
当任务正在运行时-可能是20分钟-我相信该字符串有两个句柄。一个保存在内部SetThreadName,另一个保存在隐藏的临时文件中。
一切都很好。
然后,当任务结束且线程名称设置为时'Idle',SetThreadName()释放原始字符串并分配文字Idle。
但是:我相信隐藏的本地临时文件仍然保留该字符串的句柄,且refcount = 1,因此它将占用空间,直到过程返回或下一循环来覆盖该隐藏的本地临时文件,释放旧值。
在此期间,程序无法访问它,无法将其显式释放,并且没有用处,但仍在消耗内存。
对于大多数过程而言,这无关紧要,因为它们的开始和结束都相对接近,因此所有内容都可以一次发布,但是在循环服务器应用程序中,这些过程可能会停留更长的时间。这导致我们内存碎片。
在实际的应用程序中,它更像是:
SetThreadName(tsk.Name + '-' + FormatDateTime('mm/dd/yy hh:nn:ss', Now)); …Run Code Online (Sandbox Code Playgroud)