FastMM是否能检测到所有的内存泄漏?

4
最近有人建议我(为什么我的程序永远不会释放内存?)我的程序可能存在内存泄漏。我已将FastMM设置为aggressive,并且在关闭程序时未报告任何内存泄漏。
无论如何,我想知道是否有可能存在FastMM检测不到的内存泄漏?
更新:我个人不使用Win API来分配内存。但是我担心我使用的一些第三方组件(不多)可能会使用它。您能告诉我所有可能无法被FastMM拦截的API调用吗?我将在我的代码中搜索它们。谢谢。
Delphi 7,Win 7 32位 FastMM 4.97 我对接口不感兴趣。

1
@Altar 我刚刚编写了一个应用程序,它分配一块内存,将其填充为零,然后释放它。根据Process Explorer报告的工作集统计信息,工作集会增加,然后返回到起始水平。我正在使用默认的FastMM和纯净的D2010。 - David Heffernan
1
@Altar 我问你,为什么你首先要找FastMM的问题而不是先检查你自己的代码呢?FastMM的使用非常广泛,我倾向于从它能够很好地发挥作用的角度出发。 - David Heffernan
@Altar 最后,你试过我基于MSVCRT的MM吗?我在你的另一个问题中发布了它。我敢打赌它的表现与FastMM相同,也许这可以说服你停止在那里寻找问题并查看你自己的代码。 - David Heffernan
1
@David 我认为Altar并没有声称FastMM是问题的根源。此外,一定是他代码中的某些东西引起了这个问题,而Altar正在寻找一种方法来找出问题所在。 - Eugene Mayevski 'Callback
@Eugene之前的问题提到了FastMM,考虑到之前的帖子,这个线程会更有帮助。 - David Heffernan
显示剩余6条评论
6个回答

4

FastMM是在Windows内存管理之上的一层。显然,如果您(或某个组件或其他东西)使用Windows API来分配内存,则此类分配将绕过FastMM,您将无法跟踪它。顺便说一下,Delphi内存管理器本身使用该API来分配内存块。因此,如果您需要查看该级别的分配情况,则FastMM不足够-您必须使用诸如AQTime和类似工具(如我在先前的问题中建议的那样)。


嗨,尤金。感谢您的确认。不,我不使用Windows API来分配内存。 - Gabriel
2
@Altar 你不需要,但可能有一些组件需要。 - Eugene Mayevski 'Callback
你是对的。我打算在我使用的第三方代码中搜索这种API调用。 - Gabriel

3

我从未见过FastMM无法检测到内存泄漏。


很想听一下关于这个负评的解释。也许这里有人有FastMM无法检测到内存泄漏的经验,与我们分享一下会很好。 - David Heffernan
我没有点踩,但是我确实对另一个FastMM神话有不好的经历。对于我的主要代码库来说,它比原始的MM慢得多。 - Marco van de Voort
@Marco,我对于被踩并没有什么问题,只是如果没有解释的话,那么就无法学习。我喜欢SO的原因是我可以学到很多东西。至于FastMM的性能,我只在重度线程争用下遇到过问题,这就是为什么我使用MSVCRT中的malloc。旧版的Borland MM在地址大于2GB时会发生灾难性错误,这对我来说是一个停滞不前的问题。 - David Heffernan
@DavidHeffernan David,我记得在StackOverflow上看到过你的回复,其中包含了你使用的非常简单的基本MemoryManager代码。但是我找不到那篇帖子了。你还记得那个答案是哪个吗?非常感谢!!!很抱歉这样联系你。 :-) - santiagoIT
@santiago 这些天我在我的应用程序中使用一个不同的mm,它专门为和NUMA良好地配合设计。 - David Heffernan
@santiago 这是我自己编写的程序,它专门针对我的应用行为进行了定制。它基于HeapAlloc Win32 API开发,并且每个线程使用一个堆。或者也可能是每个NUMA节点使用一个堆,我现在记不清了。 - David Heffernan

3
不,只有由FastMM分配的内存泄漏。
编辑:也许答案看起来被包裹了,但实际上并没有!如果任何人检查FastMM是如何制作的,就会发现每个内存分配指针都被推送(并在FreeMem中弹出)到其中一个堆栈中(堆栈有多个,取决于内存大小),因此在关闭应用程序时,FastMM仅检查堆栈,如果堆栈中有任何内容,则报告内存泄漏!

不是这样的。我检查了代码(包括第三方代码)中分配内存的API调用,并发现没有这些调用。 - Gabriel

3
有几种可能的原因:(适用于任何内存管理器)
- 主程序循环泄漏内存,但是释放了一些在关闭时被释放的东西。 - 最简单的情况是记录到备忘录。备忘录变得越来越大,但在关闭时被销毁。 - 内存分配在 fastmm 的控制之外。 - 直接从 windows 分配 - 在 dll 等中分配的内存。 - 堆碎片。内存管理器保留了大块已分配的内存(例如,因为它仍然包含小部分分配)。结果:应用程序不使用它,但也没有释放给操作系统。运行时/内存管理器会将其保留下来。 - fastmm 应该更能抵御这种现象,但如果有疑问,请尝试打印堆管理器信息以查看是否是这种情况。

2

FastMM 无法检测通过 FastMM 以外分配的内存泄漏。

这包括您使用的第三方库或 DLL 中的 GlobalAlloc 调用。
编辑: Microsoft 的 MSDN 提供了一个内存分配方法列表

事实上,这就是我在之前回答你有关 FastMM 的问题中所提到的问题。我的回答链接在此

您可以使用像 VMMap 这样的工具来跟踪 FastMM 无法检测到的内存泄漏。

--jeroen


我现在要搜索malloc和GlobalAlloc!有人知道我应该寻找哪些类似的调用吗? - Gabriel
我只找到了两个使用GlobalAlloc的库:Melander Gif和Melander DragAndDrop。我在这个项目中没有使用它们。因此,FastMM应该能够检测到所有的内存泄漏。 - Gabriel
@Altar:几乎任何非Delphi COM对象和C DLL都将使用非FastMM内存分配。 - Jeroen Wiert Pluimers
非常感谢您提供的列表,Jeroen。到目前为止,我已经检查了malloc和GlobalAlloc的代码。我知道“几乎任何非Delphi COM对象和C DLL都将使用非FastMM内存分配”,但我个人不使用COM,也不使用外部C DLL。 - Gabriel

2
已经有很多好的答案了,但还有一点没有被提到...
有许多“泄漏”不会被大多数内存泄漏检测器检测到,因为内存确实被释放了,但是在很长一段时间后才被释放。例如,在TObjectList中堆叠的对象。对象被放置在对象列表中,但在使用完它们之后,您并没有释放它们。它们将在对象列表被销毁时(例如应用程序关闭,假设OwnsObject = True)被销毁。由于对象实际上已被释放,因此对象并未“泄漏”,但仍会使您的应用程序随着时间的推移使用越来越多的内存。
FastMM不会报告这些问题,因为它只进行“全面运行”分析。要检测这些问题,您需要一个内存泄漏检测器,允许进行部分运行分析,即在执行期间分析A点和B点之间“泄漏”的内容。Eugene提到的AQTime可以进行此类检查。但请注意,这需要进行一些分析,因为这将产生许多错误警报(几乎所有的“realloc”操作都将被标记为泄漏)。

实际上,我有存储在TObjectList中的对象,并且我理解您的观点,但它不适用于我的情况。我使用的对象与我创建的MDI子窗体相关联(数百个)。MDI子窗体正在创建这些对象。当我释放MDI窗体时,它们会释放所有对象。但是,除此之外,您的示例非常可靠。 - Gabriel
1
Ken,从实际意义上讲,这不是内存泄漏 - 你仍然有每个对象的引用。如果你不再需要它们,抓住这些东西只是糟糕的编程习惯。 - Мסž
因此在“泄漏”周围加上引号。它们不是真正的泄漏,但它们具有与真正的泄漏完全相同的后果/症状。它们也经常被忽视,因为它们很难找到。而且这并不一定是糟糕编程的结果,在许多情况下,除了完整的引用计数实现之外,没有其他方法可以确保对象不会超出其有用性期限。有时,这样的实现是被禁止的(因为系统架构师并不总是最聪明/最有知识的人。我曾经在不久的过去被禁止在系统中使用委托(即事件))。 - Ken Bourassa

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