监控 Delphi 应用程序中的内存使用情况
我从一位离开公司的程序员那里继承了一个非常大的子系统,首要任务是阻止该进程耗尽内存。
基本上,它是一个数据集的循环,在其中我们创建和销毁一个数据模块,该模块会关闭并执行大量工作。只要创建了这个数据模块,你就可以在任务管理器中看到内存使用一直在攀升,直到爆掉。我似乎记得几年前读过的一篇文章,人们不应该完全相信任务管理器报告的内容,因为这些值是估计值而不是实时的。所以我正在寻找替代方案。
这是我尝试过的:
- ReportMemoryLeaksOnShutdown := True 在我的主项目文件中,但它什么也不返回。因此,它要么不监视动态加载的包中的内存泄漏,要么在应用程序关闭之前释放内存。
- AQ时间。这应该是一个非常哇的产品,但我发现它完全没有给人留下深刻的印象。如果我使用分配分析器,我最终会得到数百行,其中不包含任何有用的内容。只是内存地址、大小和类似于“VCL 标准分配”的内容。据说它按常规分解信息,但我只是得到一个没有任何常规信息的平面列表。所以我认为这不起作用。
是否有其他工具可以帮助我跟踪内存的分配位置和未释放位置?我一直在各处注释掉一些功能,以查看问题消失的地方,并检查显式分配的所有内容是否都已释放,但我仍然存在泄漏,这可能是一个相当令人沮丧的过程。
I inherited a very large subsystem from a programmer that left the company and the first order of business is to stop the process from running out of memory.
Basically, it is a loop through a dataset, within which we create and destroy a data module that goes off and does lots of work. As long as this data module is created, you can see memory use climbing all the time in Task Manager until it blows up. I seem to recall from an article I read years ago that one shouldn't fully trust what is reported by Task Manager, as the values are estimates and not real-time. So I am looking for alternatives.
Here's what I have tried:
- ReportMemoryLeaksOnShutdown := True in my main project file, but it returns nothing. So either it doesn't monitor memory leaked in packages that are loaded dynamically, or the memory gets freed before the app closes.
- AQTime. This is supposed to be a very wow product, but I find it completely underwhelming. If I use the allocation profiler, I end up with hundreds of lines containing nothing useful. Just a memory address, size and something along the lines of "VCL standard allocation." It supposedly breaks down the information by routine, but I just get a flat list with no routine info whatsoever. So I don't think it works.
Is there another tool that can help me trace where this memory is allocated and not freed? I've been commenting out little bits of functionality all over the place to see where the problem goes away and checked that everything that is explicitly allocated gets freed, but I still have a leak and it can be quite a frustrating process.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
FastMM 包含一个简单的 GUI,可在应用程序运行时显示内存使用情况。
示例项目位于
Demos/Usage Tracker
目录中。FastMM includes a simple GUI which displays memory usage while the application is running.
An example project is located in the
Demos/Usage Tracker
directory.我绝对会使用 AQTime,而不是其他任何东西来确定内存使用信息。以下是我希望您能找到的内存使用信息的示例:
首先,让我们先解决一些显而易见的事情:
A. 您必须遵循 AQTime 的说明并设置项目设置,包括编译器和链接器设置,如帮助文件中详细记录的那样。特别是,您需要在链接器选项中使用 Turbo Debugger (TD32) 符号,以及为项目的任何其他调试版本设置的所有其他选项设置。
B. 在将其用于您自己的应用程序之前,您应该先尝试教程。
简而言之,我大量使用AQTime,当我遇到问题时,它们都是可以解决的,所以不要放弃AQTime。如果您无法让大型应用程序运行,请首先学习如何测试小型应用程序、演示或教程练习。
更新:我刚刚亲自测试过它,我发现我什至无法按照描述的方式使用分配分析器进行 AQTime 7 的基本演示。我使用的是 AQTime 7.10.380 专业版。
I absolutely would use AQTime, and NOTHING ELSE to determine memory usage information. Here is an example of the memory usage information I would expect you could find:
First things first, let's get the obvious things out of the way:
A. You have to follow AQTime's instructions and set your project settings up, including your compiler and linker settings, as documented well in the help files. Especially you need the Turbo Debugger (TD32) symbols in your linker options, and all the other options setup as you would set up for any other debug build of your project.
B. You should try a tutorial first, before you use this with your own app.
In short, I've used AQTime heavily, and when I've had problems, they have been solveable, so don't give up yet on AQTime. If you can't get your big app working, start by learning how to test a small app, a demo, or a tutorial exercise.
Update: I have just tested it out myself, and I find that I am having trouble even making a basic demo of AQTime 7 with Allocation profiler work as described. I am using AQTime 7.10.380 pro.
要监视应用程序内存使用情况,您可以使用一些 sysinternals 工具(进程资源管理器、VMMap、Rammap)来查看从操作系统的角度来看,但是像 AQTime 这样的工具实际上会告诉你谁分配了内存,何时何地,只要你正确配置和使用它 - 它有一个初始陡峭的学习曲线,仔细阅读文档,它不是一个工具“运行并阅读 结果”。
可能不是任何泄漏导致应用程序崩溃,可能只是加载并在内存中保存了太多数据。
您很有可能在内存中加载一个巨大的数据集,或者类似的东西,例如,双向数据集将缓存以前的记录以允许向后导航,而单向数据集不会并且将使用更少的内存。在为 varchar 字段等设置内存时,某些库比其他库更有效(有些库可能总是分配 varchar 字段大小,其他库可能更聪明,只为给定的记录字段分配空间,尽管这使得记录更改的管理更加方便)难的)。这可能是中间结果在内存中保存太久、数据结构选择错误或递归太多……不看代码就很难说。
To monitor an application memory usage you could use some of the sysinternals tools (process explorer, VMMap, Rammap) to look at it from an operating system perspective, but tools like AQTime will actually tell you who allocated memory, when and where, as long as you configure and use it properly - it has an initial steep learning curve, read the documentation carefully, it's not a tool "run and read the results".
It may not be any leak to blow up the app, it could be it is just loading and keeping in memory too much data.
There are good chances you're loading a huge dataset in memory, or soemthing alike, for example a bidirectional dataset will cache previous records to allow for backwards navigation, a unidrectional one will not and will use far less memory. Some libraries are more efficient than others when setting up memory for varchar fields and the like (some may always allocate the varchar field size, other may be smarter and just allocate the space for a given record field, although that makes management of record changes more difficult). It could be intermediate result kept in memory for too long, the wrong choice of data structure or too much recursion... difficult to say without looking at the code.
在 About.com 上找到了一些用于 Delphi 内存泄漏的工具:http://delphi。 about.com/od/toppicks/tp/aatpmemleak.htm
Found some tools here on About.com for Delphi mem leaks: http://delphi.about.com/od/toppicks/tp/aatpmemleak.htm
问题很可能是您在循环访问数据集时将数据集保存在内存中,如果您有数十万(或数百万)条记录,则这可能会超过 1 GB。我似乎记得一个数据集属性,UniDirectional,它确保可以随时释放内存,因为如果设置了此属性,则无法返回到数据集中的上一条记录(像正常情况一样)。
编辑:我认为这仅适用于 BDE,但如果我没有记错的话,dbExpress 默认使用单向数据集。
The issue is most likely that you are holding the dataset in memory as you loop through it, and if you have hundreds of thousands (or millions) of records this can exceed 1 GB. I seem to recall a dataset property, UniDirectional, which ensures that memory can be released as you go because you cannot go back to the previous record in the dataset (like normal) if this property is set.
Edit: I think that this was only for the BDE, but dbExpress uses Unidirectional datasets by default if I am not mistaken.