【问题标题】:FastMM and Dynamically loaded DLLsFastMM 和动态加载的 DLL
【发布时间】:2010-06-07 12:10:07
【问题描述】:

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

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


一些补充信息:

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

其他问题:

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

【问题讨论】:

    标签: delphi dll fastmm


    【解决方案1】:

    摘自FastMM4options.inc 文件。

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

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

    {允许共享内存管理器 在主应用程序和 DLL 之间 也是用 FastMM 编译的。 这允许您传递动态数组 和长字符串到 DLL 函数 提供两者都被编译使用 快速MM。只有在 应该共享的库 内存管理器是用 “AttemptToUseSharedMM”选项集。 请注意,如果主应用程序是 单线程和DLL是 您必须设置的多线程 主程序中的 IsMultiThread 变量 应用程序为真,否则将崩溃 当发生线程争用时。笔记 静态链接的 DLL 文件是 在主程序之前初始化 应用程序,所以主要应用程序 很可能最终会静态地共享一个 加载 DLL 的内存管理器,而不是 另一种方式。 }

    {.$define ShareMM}

    {允许共享内存管理器 通过 DLL 与其他 DLL(或主 如果这是一个静态的应用程序 加载的 DLL) 也被编译 使用 FastMM。设置此选项 关心动态加载的DLL, 因为如果共享的 DLL 它的 MM 被卸载并且任何其他 DLL 还在分享MM然后 应用程序将崩溃。这个设置 仅与 DLL 库相关 并要求 ShareMM 也设置为 有什么影响。分享只会 如果应该的图书馆工作 共享内存管理器是 与编译 “AttemptToUseSharedMM”选项集。 请注意,如果 DLL 是静态的 链接然后它们将被初始化 在主应用程序之前和 那么DLL实际上将共享它的MM 与主应用程序。这 除非 ShareMM 是,否则选项无效 也设置了。}

    {.$define ShareMMIfLibrary}

    {定义它以尝试共享 主应用或其他的MM 在同一进程中加载​​ DLL 是用 ShareMM 集编译的。什么时候 共享内存管理器,内存 共享者造成的泄密不会 自动释放。考虑到 静态链接 DLL 的帐户 在主程序之前初始化 应用程序,所以设置共享 相应的选项。}

    {.$define AttemptToUseSharedMM}

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

    {$定义 EnableBackwardCompatibleMMSharing}

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • uses 子句中的 FastMM 和 SimpleShareMem 都有吗?包含所有项目、主机和 dll 吗?
      【解决方案3】:

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

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

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

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

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

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

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

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

      【讨论】:

        【解决方案4】:

        Afaik 有 sharemm,它是 fastmm 的一个版本,可以在 DLL 边界上共享。

        【讨论】:

          【解决方案5】:

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

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

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

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

          【讨论】:

          • ShareMM 不是默认的,你必须包含它。
          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-22
            • 1970-01-01
            • 2018-11-09
            • 2013-03-13
            • 1970-01-01
            相关资源
            最近更新 更多