FastMM和动态加载的DLLs

3
我有一个主机应用程序,在启动时加载了十几个库。我想从Delphi 7的默认内存管理器切换到完整版本的FastMM4,以获得更好的内存泄漏报告。
我应该在主机应用程序和库的uses部分中都包含FastMM4吗?共享运行时包怎么办?
一些额外的信息:
  • 我们有一个exe和20个以上的dll。每个人都共享一个单一的运行时包。
  • 我们今天不使用sharemem。至少我不知道。快速查看今天检查过的exe或dll中都没有包含ShareMem。
其他问题:
  • 我可以在所有项目中使用FastMM的inc文件中相同的选项,还是exe和dll需要不同的设置?
6个回答

8
FastMM4options.inc文件摘录。
对我来说,这意味着如果所有的包、dll和可执行文件都是使用ShareMM编译的,那么就可以替换Delphi 7默认的内存管理器。
{-----------------------内存管理器共享选项------------------------}
允许在使用FastMM编译的主应用程序和DLL之间共享内存管理器。这样可以将动态数组和长字符串传递给DLL函数,前提是两者都编译为使用FastMM。只有当预计共享内存管理器的库使用了“AttemptToUseSharedMM”选项时,共享才能生效。请注意,如果主应用程序是单线程的,而DLL是多线程的,则必须将主应用程序中的IsMultiThread变量设置为true,否则在线程争用时会崩溃。请注意,静态链接的DLL文件在主应用程序之前初始化,因此主应用程序可能会共享一个静态加载的DLL的内存管理器,而不是相反。
{$define ShareMM}
允许使用FastMM编译的DLL与其他使用FastMM编译的DLL(或主应用程序,如果这是一个静态加载的DLL)共享内存管理器。在动态加载的DLL中设置此选项时要小心,因为如果共享内存管理器的DLL被卸载,并且任何其他DLL仍然共享内存管理器,则应用程序将崩溃。此设置仅适用于DLL库,并且需要同时设置ShareMM才能生效。只有当预计共享内存管理器的库使用了“AttemptToUseSharedMM”选项时,共享才能生效。请注意,如果DLL是静态链接的,则它们将在主应用程序之前初始化,然后DLL实际上会与主应用程序共享其内存管理器。此选项仅在同时设置ShareMM时才生效。
{$define ShareMMIfLibrary}
将此选项定义为尝试共享主应用程序或其他在同一进程中使用ShareMM设置编译的DLL的内存管理器。共享内存管理器时,由分享者引起的内存泄漏不会自动释放。请注意,静态链接的DLL会在主应用程序之前初始化,因此请相应地设置共享选项。
{$define AttemptToUseSharedMM}
将此选项定义为启用向后兼容性,以便使用Delphi 2006和2007以及早期FastMM版本使用的内存管理器共享机制。
{$define EnableBackwardCompatibleMMSharing}

3
您需要的是SimpleShareMem。它包含在FastMM软件包中。确保您的应用程序和DLL都使用它以及FastMM4,位于它们的uses从句中的顶部。这可以确保它们都共享相同的堆,而不是使用单独的堆。
当然,只有在您需要在应用程序和库之间传递动态内存(如字符串或对象)时才需要共享内存。如果不需要,则不需要SimpleShareMem,但我仍建议将库切换到FastMM作为内存管理器,以提高性能和稳定性。

2
在所有项目中,包括主程序和dll,使用FastMM和SimpleShareMem? - Vegar

1

由于“每个人都在共享一个运行时包”,我建议使用我正在使用的方法。简单地将FastMM4添加到您的共享运行时包中(当然,您需要在每个库和主机应用程序中的“using”声明中放置FastMM4)。

这种方式有一些优点,例如:

  • 简单的方法来开启/关闭FullDebugMode [和其他选项]。不需要重新编译项目,只需重新编译共享包即可在整个应用程序(包括dll)中切换FullDebugMode,因为FastMM仅被实例化一次。

  • 没有版本问题。当您更新FastMM(一旦使用,它就成为整个应用程序和插件的关键组件)时,您不必再次构建整个构建(应用程序和插件)。再次更新共享包就足够了。

  • 卸载插件时没有内存管理器问题。我曾经遇到过一些问题,当第一个插件库被卸载时,FastMM被卸载,从而导致应用程序关闭时出现大量错误。

  • 没有跟踪问题-如果发生任何内存泄漏或其他内存问题,即使错误发生在DLL代码中,您也将获得有效的调用堆栈。

以下是我在FastMM4Options.inc中使用的(非标准)选项,以便按照上述描述使整个过程正常工作。

{$define NeverUninstall} {$define UseRuntimePackages} {.$define ShareMM}

我相信其余部分没有改变,但如果有什么问题,这里是完整的文件: http://pastebin.4programmers.net/693


0
据我所知,有一个叫做sharemm的版本,它是fastmm的一种在DLL边界上共享的方式。

0
如果您的应用程序使用运行时包编译,那么无需进行任何其他操作,因为运行时包只使用一个内存管理器。您只需要在uses列表中首个单元(最好是主应用程序代码)中指定所选内存管理器即可。所有其他运行时包都不需要修改,它们将自动使用正确的内存管理器,无论该内存管理器是什么。
如果您的应用程序没有使用运行时包,则每个DLL都有自己的内存管理器。默认情况下,它们都使用其默认内存管理器,如果我没记错的话,这是共享MM,也就是说,您可以将字符串等数据传输到和从DLL中进行传递。如果您想将默认的MM替换为另一个共享MM,则需要将新的内存管理器作为uses列表中的首个单元,添加到您想要共同工作的每个DLL或EXE中。
区别在于运行时包中的共享发生在包级别上。即使非共享内存管理器也会被共享。而没有运行时包时,每个DLL都使用独立的内存管理器,只有这些独立的内存管理器合作时才能实现共享。

我的观点是,除非您的应用程序与dll密切交互(即:在dll中具有表单和组件),否则最好的方法不是依赖于共享内存管理器,而是正确地管理内存,跟踪谁创建了什么并在实例化它们的同一库中删除对象。这并不难。只需返回接口而不是对象,返回shortstrings(固定长度)或将数据复制到提供的缓冲区中而不是返回字符串等。不要返回调用者将释放的内容,也不要接受调用方必须释放的内容,这样基本上就安全了。这不仅解决了所有可能的内存管理器问题,还可以让您使用任何语言编写dll。


ShareMM不是默认的,你必须将其包含进来。 - Ondrej Kelle

0
你有两个选择:继续使用ShareMem单元和FastMM分发中找到的BorldMM.dll替代品,或修改可执行文件和DLL以包含FastMM内存管理器,将该单元作为第一个。你还应该根据需要调整FastMM4Options.inc中的一些$DEFINEs,它们在那里有很好的解释。据我所知,运行时包使用安装的内存管理器。

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