3

我有一个主机应用程序,它在启动时加载了十几个库。我想从 Delphi 7s 默认内存管理器切换到 FastMM4 的完整版本,以获得更好的内存泄漏报告。

我应该在主机应用程序和库的使用部分中包含 FastMM4 吗?共享运行时包呢?


一些补充信息:

  • 我们有一个 exe 和 >20 个 dll。每个人都在共享一个运行时包。
  • 我们今天不使用 sharemem。不是我知道的。ShareMem 不包含在我今天快速浏览的 exe 或 dll 中。

附加问题:

  • 我可以在所有项目的 fastmems inc 文件中使用相同的选项,还是 exe 和 dll 需要不同的设置?
4

6 回答 6

8

文件摘录FastMM4options.inc

对我来说,这意味着如果你所有的包、dll 和可执行文件都是用 ShareMM 编译的,那么应该可以替换 Delphi 7s 的默认内存管理器。

{------------------------------------内存管理器共享选项---------- --}

{允许在主应用程序和同样使用 FastMM 编译的 DLL 之间共享内存管理器。这允许您将动态数组和长字符串传递给 DLL 函数,前提是它们都被编译为使用 FastMM。只有在使用“AttemptToUseSharedMM”选项集编译应该共享内存管理器的库时,共享才会起作用。请注意,如果主应用程序是单线程的并且 DLL 是多线程的,则您必须将主应用程序中的 IsMultiThread 变量设置为 true,否则会在发生线程争用时崩溃。请注意,静态链接的 DLL 文件在主应用程序之前初始化,因此主应用程序很可能最终共享一个静态加载的 DLL 的内存管理器,而不是相反。}

{.$define ShareMM}

{允许 DLL 与同样使用 FastMM 编译的其他 DLL(或主应用程序,如果这是一个静态加载的 DLL)共享内存管理器。在动态加载的 DLL 中设置此选项时要小心,因为如果共享其 MM 的 DLL 被卸载并且任何其他 DLL 仍在共享 MM,那么应用程序将崩溃。此设置仅与 DLL 库相关,并且还需要设置 ShareMM 才能生效。只有在使用“AttemptToUseSharedMM”选项集编译应该共享内存管理器的库时,共享才会起作用。请注意,如果 DLL 是静态链接的,那么它们将在主应用程序之前初始化,然后 DLL 实际上将与主应用程序共享其 MM。

{.$define ShareMMIfLibrary}

{定义此项以尝试在使用 ShareMM 集编译的同一进程中共享主应用程序的 MM 或其他加载的 DLL。共享内存管理器时,共享器导致的内存泄漏不会自动释放。考虑到静态链接的 DLL 在主应用程序之前初始化,因此请相应地设置共享选项。}

{.$define AttemptToUseSharedMM}

{定义此项以启用 Delphi 2006 和 2007 以及较旧的 FastMM 版本使用的内存管理器共享机制的向后兼容性。}

{$define EnableBackwardCompatibleMMSharing}

于 2010-06-07T12:34:07.573 回答
3

您要查找的内容称为 SimpleShareMem。它包含在 FastMM 包中。确保您的应用程序和您的 DLL 都在使用它,并且在它们的uses子句顶部使用 FastMM4 。这确保它们都共享同一个堆而不是使用单独的堆。

当然,共享内存仅在您要在应用程序和库之间传递动态内存(例如字符串或对象)时才是必需的。如果没有,那么您不需要 SimpleShareMem,但我仍然建议将库切换到 FastMM 作为内存管理器,以提高性能和稳定性。

于 2010-06-07T12:34:26.673 回答
1

因为“每个人都在共享一个运行时包”。我会推荐我正在使用的方法。简单地说,将 FastMM4 添加到您的共享运行时包中(当然,无论如何,您都需要将 FastMM4 放入每个库和宿主应用程序的“使用”声明中)。这种方式有一些优点,例如:

  • 打开/关闭 FullDebugMode 的简单方法 [当然还有其他选项]。不需要重新编译项目,仅重新编译共享包就足以在整个应用程序(包括 dll 的)中切换 FullDebugMode,因为 FastMM 仅实例化一次。

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

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

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

以下是我在我的 FastMM4Options.inc 中使用的(非标准)选项,以使整个事情如上所述。

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

好吧,我相信其余部分保持不变,但如果有问题,这里是完整文件: http: //pastebin.4programmers.net/693

于 2010-06-09T11:00:18.700 回答
0

如果您的应用程序是使用运行时包编译的,则不需要额外的操作,因为运行时包始终只使用一个内存管理器。您只需要指定一次您选择的内存管理器,最好在主应用程序代码中作为使用列表中的第一个单元。所有其他运行时包都不需要修改,它们将自动使用正确的内存管理器,无论该内存管理器是什么。

如果您的应用程序是在没有运行时包的情况下编译的,那么每个 dll 都有自己的内存管理器。默认情况下,它们都使用默认的内存管理器,如果我没记错的话,它是一个共享 MM,也就是说,您可以将字符串传输到 dll 或从 dll 传输。如果你想用另一个共享的 MM 替换默认的 MM,你需要在你想一起工作的每个 dll 或 exe 的使用列表中包含新的内存管理器作为第一个单元。

不同之处在于运行时包共享发生在包级别。即使是非分享MM也会分享。如果没有运行时包,每个 DLL 都使用单独的 MM,并且只有当这些单独的内存管理器合作时,您才能获得共享。

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

于 2010-06-07T13:10:30.660 回答
0

Afaik 有 sharemm,一个用于共享 DLL 边界的 fastmm 版本。

于 2010-06-07T12:21:16.487 回答
0

Ypu 有两个选择:继续使用您在 FastMM 发行版中找到的 ShareMem 单元和 BorldMM.dll 替换,或者修改可执行文件和 DLL 以包含FastMM 内存管理器,将单元放置为第一个单元。您还应该根据您的需要定制您在 FastMM4Options.inc 中找到的一些 $DEFINE,它们在那里得到了很好的解释。AFAIK 运行时包使用已安装的内存管理器。

于 2010-06-07T19:08:38.563 回答