在Delphi应用程序中监视内存使用情况

8
我从一位离开公司的程序员那里接手了一个非常大的子系统,首要任务是防止进程耗尽内存。
基本上,这是一个数据集的循环,其中我们创建和销毁一个数据模块,该模块会执行大量工作。只要创建此数据模块,您就可以在任务管理器中看到内存使用情况一直在上升,直到它崩溃。我似乎记得几年前读过一篇文章,说不应该完全信任任务管理器报告的内容,因为这些值只是估计值,而不是实时值。所以我正在寻找替代方案。
以下是我尝试过的方法:
1. 在我的主项目文件中设置ReportMemoryLeaksOnShutdown := True,但它没有返回任何结果。因此,它要么不监视动态加载的包中泄漏的内存,要么是在应用程序关闭之前释放了内存。
2. AQTime。这被认为是一个非常棒的产品,但我发现它完全不起作用。如果我使用分配分析器,我最终会得到数百行不包含任何有用信息的结果。只是一个内存地址、大小和类似于“VCL标准分配”的东西。它据说可以按例程分解信息,但我只得到了一个平面列表,没有例程信息。所以我认为它不起作用。
是否有其他工具可以帮助我跟踪分配并未释放的内存?我一直在随处注释功能的小部分,以查看问题消失的地方,并检查所有明确分配的内容是否被释放,但我仍然有一个泄漏问题,这可能是一个相当令人沮丧的过程。

数据集加载有多重?你确定那不是数据量太大了吗? - Marco
3
ReportMemoryLeaksOnShutdown在关闭时报告未释放的内存泄漏。在运行时报告泄漏更加困难。 - David Heffernan
1
AQTime 对我来说是一个非常棒的产品。我认为你应该花更多时间去了解它,因为在我长期寻找更好的内存泄漏调试器的过程中一直徒劳无功。 - r4w8173
@Cobus,你确定是内存不足而不是资源不足(窗口/字体/位图句柄)? - Johan
@Cobus,听起来就像我在答案中描述的问题。 - Misha
显示剩余3条评论
5个回答

11

FastMM包含一个简单的GUI,可在应用程序运行时显示内存使用情况。

示例项目位于Demos/Usage Tracker目录中。


4
你可以将使用跟踪器表单直接包含到你自己的项目中,我会向你展示一个实时的图形表示,它会不断更新你的内存情况。非常棒。我通常会在 {$IFDEF DEBUG}..{$ENDIF} 之间包含它,这样它只会出现在我的调试构建中。 - Wouter van Nifterick

3
我绝对会使用AQTime来确定内存使用信息,不会使用其他任何工具。以下是我期望您可以找到的内存使用信息示例:
1. 使用GetMem、TObject.Create等函数精确分配内存的行号。 2. 各种类类型使用的对象计数器和总内存使用情况。
首先,让我们把显而易见的事情搞定:
A. 你必须按照AQTime的说明设置项目设置,包括编译器和链接器设置,这在帮助文件中有很好的文档说明。特别是需要在链接器选项中设置Turbo Debugger(TD32)符号,以及所有其他选项设置,就像为项目的任何其他调试版本设置一样。
B. 在使用自己的应用程序之前,您应该先尝试一下教程。
简而言之,我已经广泛地使用了AQTime,当我遇到问题时,它们是可解决的,所以不要放弃AQTime。如果您无法使大型应用程序正常运行,请从学习如何测试小型应用程序、演示文稿或教程练习开始。
更新:我刚刚亲自测试了一下,发现我甚至无法使AQTime 7的Allocation profiler基本演示工作如描述的那样。我正在使用AQTime 7.10.380专业版。

1
要监视应用程序的内存使用情况,您可以使用一些sysinternals工具(如进程资源管理器、VMMap、Rammap)从操作系统的角度来查看它,但像AQTime这样的工具实际上会告诉您是谁分配了内存,何时以及在哪里,只要您正确地配置和使用它-它有一个初始陡峭的学习曲线,请仔细阅读文档,它不是一个“运行并阅读结果”的工具。 可能没有任何泄漏导致应用程序崩溃,可能只是加载并将太多数据保留在内存中。 很有可能您正在加载大量数据集,或者类似的东西,例如双向数据集将缓存先前的记录以允许向后导航,而单向数据集则不会,并且将使用更少的内存。某些库在为varchar字段设置内存时比其他库更有效(有些可能总是分配varchar字段大小的空间,而其他库可能更加智能,只分配给定记录字段的空间,尽管这使得记录更改的管理更加困难)。它可能是在内存中保留了太长时间的中间结果,选择错误的数据结构或递归过深...没有查看代码很难说。

只要你正确地配置和使用它 - 这就是关键。如果你学会如何使用它,它将会给你想要的结果。 - mj2008

0

我今天早些时候看到了这个,但是其中两个工具自 Delphi 7 以来没有得到显著更新,另外两个也不是真正针对内存问题进行跟踪的。看起来大家的共识是我应该再次尝试 AQTime,这次更加仔细地按照说明操作。 - Cobus Kruger

0
问题很可能是您在循环遍历数据集时将其保存在内存中,如果有数十万(或数百万)条记录,这可能会超过1 GB。我记得有一个数据集属性UniDirectional,它确保可以释放内存,因为如果设置了此属性,则无法返回到数据集中的上一条记录(与正常情况不同)。
编辑:我认为这仅适用于BDE,但如果我没有记错,dbExpress默认使用Unidirectional数据集。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接