Delphi:FastMM虚拟内存管理参考?

4
我最近遇到了一个问题(请参见我的上一篇问题),这促使我更加仔细地研究Delphi应用程序中的内存管理。在我的第一次探索之后,我有两个问题。
我已经开始使用FastMMUsageTracker,并注意到以下情况。当我打开一个文件供应用程序使用(也创建一个表单等等)时,应用程序可用虚拟内存的变化与“FastMM4分配”的内存变化之间存在显着差异。
首先,我对术语有点困惑:为什么会有一些FastMM-分配的内存和一些“系统分配”(和保留)的内存?既然FastMM是内存管理器,为什么系统负责分配一些内存?
此外,我如何获得有关已分配该内存的对象/结构的更多详细信息? VM图表只有在显示“系统分配”,“系统保留”或“FastMM分配”的内存量时才有用,但没有链接到实际需要该内存的对象。例如,是否可以在执行中获取类似于FastMM在关闭应用程序时生成的报告?显然,FastMM将该信息存储在某个地方。
作为对我来说的额外奖励,如果人们能够推荐一本好的参考书籍或网站,那么这也将受到高度赞赏。网络上有大量的信息,但通常非常特定于案例和专家。
谢谢!
PS:这不是关于查找泄漏的问题,在那里没有问题,只是尝试更好地理解内存管理并为未来做出预防措施,因为我们的应用程序使用越来越多的内存。
3个回答

3
有些问题很容易回答,至少其中一个是这样的!
为什么有一些由FastMM分配的内存和一些“系统分配”的(并且保留)内存?既然FastMM是内存管理器,为什么系统负责分配一些内存?
您在Delphi中编写的代码只是运行在进程中的一部分。您使用DLL形式的第三方库,最显著的是Windows API。例如,每当您创建一个Delphi窗体时,都会在其后面使用许多窗口对象来占用内存。此内存不是由FastMM分配的,我认为这就是您问题中所谓的“系统分配”的内存。
但是,如果您想深入了解,那么这很快就会变成一个极其复杂的主题。如果您确实想深入了解Windows内存管理的实现,那么我认为您需要咨询一份严肃的参考资料。我建议阅读Mark Russinovich、David Solomon和Alex Ionescu的Windows Internals

谢谢David,我以为FastMM会接管所有内存分配,包括API调用产生的内存。看来我错了!:o) 我会获取一本那本书,看看能从中学到什么。 - Bourgui

2
首先,我对术语有点困惑:为什么会有一些由FastMM分配的内存和一些“系统分配”的(以及保留的)内存?由于FastMM是内存管理器,为什么系统负责分配一些内存?
当然,FastMM从系统获取内存来进行分配。当您的应用程序启动时,FastMM从系统获取一个内存块。当您请求使用一些内存(无论是使用GetMem、New还是TSomething.Create),FastMM尝试从第一个初始块中为您提供它。如果那里没有足够的内存,FastMM会向系统请求更多(如果可能的话,一次性地),并将其中的一部分返回给您。当您释放某些内容时,FastMM不会将该内存返回给操作系统,因为它认为您会再次使用它。它只是在内部标记它为未使用。它还尝试重新对未使用的块进行实ign,以尽可能地使它们连续,以避免不必要地回到操作系统寻求更多。 (但是这种重新排列并不总是可能的;这就是为什么您最终会出现内存碎片的原因,比如动态数组的多次调整大小,大量对象创建和释放等)
除了FastMM在您的应用程序中管理的内存之外,系统还为堆栈和堆分配了空间。每个进程在启动时都会获得一兆字节的堆栈空间,用于放置变量。这个堆栈(和堆)可以根据需要动态增长。
当您的应用程序退出时,它分配的所有内存都将释放回操作系统。(虽然在任务管理器中可能不会立即显示,但确实是如此)
就像我所知道的那样,中途生成类似于FastMM在关闭应用程序时生成的报告是不可能的。因为FastMM将其存储在某个地方并不意味着有一种方法可以从内存管理器外部访问它。您可以查看FastMMUsageTracker的源代码,以了解如何检索信息(使用GetMemoryManagerState和GetMemoryMap,在RefreshSnapshot方法中)。FastMM4的源代码也是可用的;您可以查看并查看哪些公共方法可用。
FastMM自己的文档(以readme文件、FastMM4Options.inc注释和FastMM4_FAQ.txt文件的形式)在一定程度上有助于解释它的工作原理以及可用的调试选项(和信息)。

我不确定在这种情况下“系统分配”的含义是否正确。在if AMemoryMap[LInd] = csExSysAllocated旁边的代码注释中写道:“如果该块不是由此内存管理器分配的,那么它的状态是什么?” - David Heffernan
@David,你一定比我使用的FastMM4版本更新。csExSysAllocated不在我的FastMM4.pas或UsageTracker代码中。你引用的那个注释也不在其中。我想现在是时候更新了。 - Ken White
谢谢Ken。我明白FastMM是从系统本身分配内存,但我的问题源于我错误地认为它会处理与应用程序相关的所有内存分配,除了外部DLL等。我没有意识到Windows会接管由API调用导致的任何内存分配。我确实开始研究FastMM4代码,但它非常复杂,我希望我只是错过了一个现有的函数。看来我又要深入研究了!:o) - Bourgui
@Bourgui:FastMM4 无法处理由 API 调用(Windows DLL)执行的任何分配;内存必须由同一内存管理器分配和释放,当然 Windows 自身不使用 FastMM4。 :) 操作系统以某种方式参与所有内存分配;FastMM4 只是尝试在 Delphi 代码内部进行优化(比原始的 BorlandMM 做得更好 - 这就是为什么 FastMM4 现在是默认内存管理器并被 IDE 自身使用的原因)。 - Ken White

0

如果想要查看进程使用的详细内存映射,请尝试使用www.sysinternals.com上的VMMAP(也是由David回答中提到的Mark Russinovich共同编写的)。这还允许您查看某些位置存储的内容(在选择详细行时键入control-T)。

警告:您的进程使用的内存比您想象的要多得多。您可能需要先阅读本书。


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