【问题标题】:Static or dynamic linking the CRT, MFC, ATL, etc静态或动态链接 CRT、MFC、ATL 等
【发布时间】:2010-09-19 07:16:19
【问题描述】:

早在 90 年代,当我第一次开始使用 MFC 时,我曾经动态链接我的应用程序并发布相关的 MFC DLL。这给我带来了一些问题(DLL 地狱!),我改用静态链接 - 不仅适用于 MFC,还适用于 CRT 和 ATL。除了较大的 EXE 文件之外,静态链接从来没有给我带来任何问题——那么其他人遇到过任何缺点吗?是否有充分的理由再次访问动态链接?我的应用现在主要是 STL/Boost FWIW。

【问题讨论】:

    标签: c++ mfc linker


    【解决方案1】:

    我听到的关于此问题的大多数答案都涉及与其他程序共享您的 dll,或者在无需修补软件的情况下更新这些 dll。

    坦率地说,我认为这些是缺点,而不是优点。当第三方 dll 更新时,它的变化足以破坏您的软件。现在,硬盘空间不再像以前那么宝贵了,您的可执行文件中多了 500k?谁在乎?

    • 100% 确定您的软件使用的 dll 版本是一件好事。
    • 100% 确定客户端不会出现依赖问题是一件好事。

    在我看来,好处远大于坏处

    【讨论】:

      【解决方案2】:

      有一些缺点:

      • 更大的 exe 大小(尤其是如果您发送多个 exe)
      • 使用依赖或假定动态链接的其他 DLL 的问题(例如:您无法作为静态库获得的第 3 方 DLL)
      • 具有独立静态链接(无跨模块分配/解除分配)的 DLL 之间的不同 c 运行时
      • 无法自动为共享组件提供服务(无法让第 3 方模块供应商更新其代码以解决问题,而无需重新编译和更新您的应用程序)

      我们为我们的 Windows 应用程序进行静态链接,主要是因为它允许 xcopy 部署,这只是通过安装或依赖 SxS DLL 的方式是不可能的,因为该过程和机制没有很好的文档记录或容易远程处理。如果您在安装目录中使用本地 DLL,它会起作用,但它没有得到很好的支持。无法在不通过远程系统上的 MSI 的情况下轻松进行远程安装是我们不使用动态链接的主要原因,但是(正如您所指出的)静态链接还有许多其他好处。各有利弊;希望这有助于列举它们。

      【讨论】:

      【解决方案3】:

      只要您将使用限制在某些库并且不使用任何 dll,那么您应该会很好。

      很遗憾,有些库无法静态链接。我拥有的最好的例子是 OpenMP。如果您利用 Visual Studio 的 OpenMP 支持,则必须确保已安装运行时(在本例中为 vcomp.dll)。

      如果你确实使用了 dll,那么你不能在没有一些严肃的体操的情况下来回传递一些项目。想到 std::strings 。如果您的 exe 和 dll 是动态链接的,则分配发生在 CRT 中。否则,您的程序可能会尝试在一侧分配字符串并在另一侧取消分配。坏事接踵而至……

      也就是说,我仍然静态链接我的 exe 和 dll。它确实减少了安装中的很多可变性,我认为这些限制非常值得。

      【讨论】:

      • 内存分配不正确。当您使用 DLL CRT 时,应用程序中只有一个 CRT,因此您可以从一个 DLL 分配并在另一个 DLL 中释放,因为它是同一个 CRT,所以它们都将进入同一个堆。
      • 是的,但是如果 exe 和 dll 都是静态链接的,那么就有两个堆。正确的?至少这是我的经验。我得告诉你,能够来回传递 std::string 或向量会让我的生活更轻松。
      • 解决 std::string 问题的方法不是胡扯。静态链接或动态链接。如果你至少有一个 C++ DLL,链接到 CRT DLL。
      【解决方案4】:

      使用 dll 的一个好处是,如果多个进程加载相同的 dll,则可以在它们之间共享其代码。这可以节省内存并缩短应用程序加载已被另一个程序使用的 dll 的加载时间。

      【讨论】:

      • 这可以通过页面重复数据删除来节省系统内存,但实际上减少了单个进程的虚拟地址空间——而不是仅将库的一部分拉入可执行文件,而是将整个库映射到进程地址空间。通过映射多个 DLL 并使用 ASLR,进程虚拟地址空间会变得碎片化,这至少对于 32 位应用程序而言会大大减少可分配的连续内存块的大小。
      【解决方案5】:

      不,这方面没有什么新鲜事。保持这种状态。

      【讨论】:

        【解决方案6】:

        绝对是。

        分配是在“静态”堆上完成的。由于分配和解除分配应该在同一个堆上完成,这意味着如果你发布一个库,你应该注意客户端代码不能调用“你的”p = new LibClass() 并使用delete p; 删除该对象本身。

        我的结论:要么屏蔽客户端代码的分配和释放,要么动态链接 CRT。

        【讨论】:

          【解决方案7】:

          有些软件许可(例如 LGPL)要求您使用 DLL 或将您的应用程序分发为用户可以链接在一起的目标文件。如果您正在使用这样的库,您可能希望将其用作 DLL。

          【讨论】:

          • 如果您使用这样的库,您可以支付赎金以进行静态链接(而不是拖着 DLL)。
          猜你喜欢
          • 2018-05-04
          • 2012-05-14
          • 1970-01-01
          • 2015-05-06
          • 1970-01-01
          • 1970-01-01
          • 2012-12-19
          • 1970-01-01
          相关资源
          最近更新 更多