如何分析Delphi应用程序中过多的内存消耗(PageFileUsage)?

4

这是对该问题的后续:FastMM或GetProcessMemoryInfo报告的内存使用差异可能是什么原因?

我的Delphi XE应用程序使用了大量的内存,有时会导致内存不足异常。我正在尝试理解为什么以及什么原因导致了这种内存使用情况,虽然FastMM报告低内存使用情况,但请求TProcessMemoryCounters.PageFileUsage时,我可以清楚地看到应用程序使用了大量内存。

我想了解是什么原因导致了这个问题,并希望得到一些关于如何处理它的建议:

  • 是否有办法知道内存中包含什么内容以及它在哪里被分配?
  • 是否有一些工具可以跟踪Delphi应用程序中每行/过程的内存使用情况?
  • 有关如何处理此类问题的任何一般建议?

编辑1:以下是FastMMUsageTracker的两个屏幕截图,指示系统已分配内存。

  • 进程开始之前:

Before process starts

  • 进程结束后:

After process ends

图例:浅红色为FastMM分配的内存,深灰色为系统分配的内存。

我想了解是什么原因导致系统使用了那么多内存。可能是通过了解这些内存中包含的内容或者引起该分配的代码行或过程来理解。

编辑2:出于多种原因,我不想使用完整版本的AQTime:

  • 我正在使用多个虚拟机进行开发,它们的许可证系统很麻烦(我已经是TestComplete的注册用户)
  • LITE版本提供的信息不足,我不会浪费钱,除非能确定完整版会为我提供有价值的信息

还有其他建议吗?


2
这个问题的答案Profiler and Memory Analysis Tools for Delphi可以帮助你。 - RRUZ
@RRUZ 看起来很有意思,但似乎所有答案都与“时间分析器”有关,几乎没有关于内存使用分析的信息。 - jonjbar
我建议您定期记录FastMM返回的灰色区域值,并将其与应用程序代码的不同位置的简短位置信息一起记录到日志文件中。我正在开发一个通用工具(VisualMM),它还显示时间线,请参见http://mikejustin.wordpress.com/。 - mjn
你可以使用试用期来查看完整版是否能给你所需的信息。 - Lars Truijens
@Lars 我可以尝试,但它能在虚拟机中安装吗?在购买之前,我无法在我的主要开发虚拟机上试用TestComplete,这有多愚蠢啊:( - jonjbar
2个回答

4
您需要使用分析器,但在许多地方和情况下,这仍然不足够。此外,在您的情况下,您需要完整功能的AQTime,而不是随附于Delphi XE和XE2中的精简版本。(AQTime价格非常昂贵,而且令人烦恼的是,它是节点锁定的,所以请不要认为我是SmartBear软件的推销员。)
事实上,人们经常错误地将AQTime Allocation Profiler误认为只是一种查找泄漏的方法。至少在工具的限制内,它也可以告诉您内存去哪里了。运行时,当消耗大量内存时,单击“运行” - “获取结果”。
下面是一个正在使用AQTime进行配置文件的示例应用程序,其Allocation Profiler显示堆中分配了多少个实例以及这些实例使用了多少内存。由于您报告了使用FastMM的低Delphi堆使用率,这告诉我AQTime按delphi类名分析的大部分能力对您来说也将无用。但是,通过使用AQTime的事件和触发器,您可能能够弄清楚应用程序的哪些区域会导致“内存使用费用”,以及何时发生这些情况以及费用是多少。尽管它可能无法自动找到导致最多内存使用的函数调用,但AQTime的实时工具可能足以帮助您缩小原因的范围。
它可以检测Delphi和C / C ++库在堆上的分配,并且可以查看某些Windows-API级别的内存分配。
请注意对象的实时计数和使用的来自堆的内存量。
通常我会通过在执行昂贵操作之前和之后测量堆内存使用情况,但在清理(释放)该昂贵操作的内存之前,尝试弄清楚特定操作的内存成本。我可以在AQTime中设置事件点,当我命中特定方法或打开旗标时,可以测量之前和之后的值,然后进行比较。
FastMM单独甚至无法检测非delphi分配或未由FastMM管理的堆分配。 AQTime没有这种限制。

@Warrent 谢谢,我尝试了你的解决方案(仅使用AQTime Lite,因为完整版太受限制或昂贵),但我看到非常不同的内存使用结果(也检查了系统内存):AQTime报告81,339,834,而TProcessMemoryCounters.PageFileUsage报告983,592,960。这是由于lite版本吗?此外,如何解释结果以获得有用的东西:VCL本机内存或已提交的虚拟内存并没有帮助很多? - jonjbar
我非常怀疑你会从LITE版本中获得很多用处,就像我在上面清楚地说明的那样!由于LITE版本缺乏对EVENTS甚至是我上面展示的相同的LIVE VIEWS的支持,因此LITE版本的使用对你的需求来说将非常有限。 - Warren P
因为完整版可以分析内存使用情况,包括 VC++ C/C++ 运行时堆 malloc 等非 Delphi 堆源。 - Warren P
约翰,我不确定你是否有其他合理的选择。如果你情急之下,你可以尝试一些“跟踪”工具,这些工具可以让你了解Windows API或其他活动所涉及的情况。SysInternals套件有很多好用的工具,可能会帮助你看到一些东西:http://technet.microsoft.com/en-us/sysinternals - Warren P
非常感谢您详细的回答,Warren。很抱歉由于AQTime许可证的问题,我无法接受它:( 问题涉及TPngImage,我无法理解它,但我用DevExpress的PNG库替换了它,现在内存使用量少多了。谢谢。 - jonjbar
显示剩余2条评论

4

另一个问题可能是堆碎片。这意味着你有足够的空闲内存,但所有的空闲块都太小了。你可以使用FastMM的源代码版本,并像这里所建议的那样使用FastMMUsageTracker.pas来直观地查看它。


这很有趣,看起来证明这不是由于空闲块引起的。这是之前的图表:http://i.imgur.com/uYFBq.png - 当内存已满时的图表:http://i.imgur.com/fpfet.png - 你有什么想法可以继续调查吗? - jonjbar
1
如果不是堆碎片问题,我建议使用像@Warren建议的AQTime等工具。 - Lars Truijens
我更新了我的问题,澄清我想避免使用AQTime。你有什么其他工具建议吗? - jonjbar
不,我不知道还有其他工具可以与Delphi一起使用并提供这种详细级别。除了FastMM,但它只会报告自己的内存。 - Lars Truijens
我接受你的答案,因为它提供了我最多的信息。问题涉及TPngImage,我无法理解它,所以我用DevExpress的PNG库替换了它,现在它使用的内存要少得多。谢谢。 - jonjbar

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