使用 Delphi 7 为什么一个简单的列表框会增加内存

Using Delphi 7 why does a simple listbox give memory buildup

我注意到在 Windows 10 的任务管理器中,使用简单的 listbox.clear 然后写入它每次都会增加内存使用量。 例如

for k:=1 to 10 do  begin
assignfile(f,'T:\Programming\WORK\PROG\crap\searchfolders.fil');
reset(f);
listbox1.clear;
while not eof(f) do
  begin
    readln(f,s);  //there are 5 lines of text in the file
    listbox1.items.add(s);
  end;
closefile(f);
MessageDlg('check memory',mtinformation,[mbok], 0); 
//it will have increased by roughly 0.5Mb

end;

所以 - 这正常吗?有关系吗;为什么这样做

应用程序内存"use" 在任何操作系统上都是一个相当模糊的概念。

如果应用程序依赖 OS 进行所有内存管理,性能将是不可接受的。

因此,大多数(如果不是全部)应用程序都在一定程度上管理自己的内存。 Delphi 应用程序肯定是这种情况。

A Delphi 应用程序管理自己的堆,从 OS 分配(相对)大块内存,然后将其分发到较小的 'pieces' 以供在应用程序中使用需要。如果应用程序用完了预分配的内存,则它必须返回以从 OS 请求更多内存。

这也意味着在任何给定时间,一些分配的内存在应用程序中未被积极使用。

随着内存使用的变化,应用程序将 return 任何多余的内存返回到 OS。例如,Delphi 应用程序的工作方式通常发生在最小化应用程序时。因此,如果您最小化然后恢复您的应用程序,您 可能 会看到内存 "in use" 发生相当大的变化。支撑这一点的机制有时用于通过触发相同的进程以响应应用程序只是 "idle" 而不是专门最小化,从而更积极地强制应用程序使用 return 内存。

但是,此类技术只是解决了在任务管理器中观察到的内存使用感知,并没有真正减少真实内存使用。

最重要的是,从 OS 的角度来看,应用程序使用的内存可能与实际使用的内存有很大不同。

在您的情况下,对正在发生的事情的简化视图是为将项目添加到列表框所需的字符串分配内存。当您清除列表框时,用于这些字符串的内存不会立即 returned 到系统,因为这非常昂贵,而是简单地标记为不再使用(它将 returned 到系统在某个时候,只是还没有)。

在循环的下一次迭代中,当需要将更多字符串添加到列表框时,高效的内存管理器(在应用程序中)可能会识别以前使用的内存,但尚未 returned到 OS,现在可以重新使用了。当然,识别这需要时间,因此简单地使用一些 "fresh" 内存可能更有效,即使这意味着向 OS 请求更多内存。

将内存返回给 OS 比请求更多更复杂(因此 'more expensive',即需要更长的时间),因为内存只能 return 成块,所以即使您只有 10% 的应用程序内存 "in use",也可能正在使用的 10% 分布在整个内存中,使得某些甚至可能是任何内存都不可能被使用return 编辑到 OS。你会经常听到这种情况被称为记忆 "fragmentation".

这就是为什么 return 将内存分配给 OS 比分配新内存的成本更高,因为必须完成工作才能确定哪些内存可以安全 returned.

返回您的场景:

经过 2 次迭代后,您累积了 轮已使用的内存,现在标记为 不再 使用(在应用程序中).然而,从 OS 的角度来看,该应用程序仍然是 "using" 内存,因为 OS 不知道应用程序自己管理该内存的内部发生了什么。重复多次,您可以轻松积累大量“已分配但当前未使用”内存。

但这通常不是您需要担心的事情 - 以及在不再需要且方便时将内存 return 存储到 OS,应用程序将 return 内存,当 告诉 由 OS 这样做时,例如,如果系统处于内存压力下。

操作系统直接支持应用程序可能 "using" 它实际上没有使用的内存并且可以在需要时被要求释放的可能性这一事实应该告诉你这不是异常。其实也在意料之中。

然而值得一提的是 Delphi 内置的内存管理器是可替换的。

Delphi7 中的默认内存管理器就足够了,但还有许多替代方案可用。其中一些是高度专业化的,但特别是一个通用内存管理器 - FastMM - 已被证明是对旧 Delphi 内存管理器的显着改进,它被采用为新的默认内存管理器Delphi 2006 年起。

它仍然作为一个开源项目免费提供,您可以轻松地将其合并到您自己的应用程序中,但是,即使在 Delphi 7(甚至更旧的版本)中也是如此。所涉及的只是添加一个单元作为 DPR 使用列表中的第一个条目。

与 Delphi7 中的默认内存管理器相比,FastMM 对内存碎片具有更高的弹性,从而提高效率并提高整体性能。它还提供额外的调试工具,例如内存泄漏检测和用于识别其他内存错误的设施,例如双重释放对象 and/or 所谓的 'dangling' 指针(在某种程度上)。

您可能会发现,在您的测试用例中使用 FastMM 可能会对您的用例中的感知内存使用产生影响,但是,出于解释的原因,这个测试用例本身并不值得关注,除非它呈现您的应用程序中的实际问题。