C++ 静态链接与动态链接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1993390/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:47:10  来源:igfitidea点击:

Static linking vs dynamic linking

c++cperformancestatic-linkingdynamic-linking

提问by Eloff

Are there any compelling performance reasons to choose static linking over dynamic linking or vice versa in certain situations? I've heard or read the following, but I don't know enough on the subject to vouch for its veracity.

在某些情况下选择静态链接而不是动态链接,反之亦然,是否有任何令人信服的性能原因?我听说过或阅读了以下内容,但我对这个主题的了解不够,无法保证其真实性。

1) The difference in runtime performance between static linking and dynamic linking is usually negligible.

1) 静态链接和动态链接在运行时性能上的差异通常可以忽略不计。

2) (1) is not true if using a profiling compiler that uses profile data to optimize program hotpaths because with static linking, the compiler can optimize both your code and the library code. With dynamic linking only your code can be optimized. If most of the time is spent running library code, this can make a big difference. Otherwise, (1) still applies.

2) (1) 如果使用使用分析数据优化程序热路径的分析编译器则不正确,因为通过静态链接,编译器可以优化您的代码和库代码。使用动态链接只能优化您的代码。如果大部分时间都花在运行库代码上,这会产生很大的不同。否则,(1)仍然适用。

采纳答案by dmckee --- ex-moderator kitten

  • Dynamiclinking can reduce total resource consumption(if more than one process shares the same library (including the version in "the same", of course)). I believe this is the argument that drives it its presence in most environments. Here "resources" includes disk space, RAM, and cache space. Of course, if your dynamic linker is insufficiently flexible there is a risk of DLL hell.
  • Dynamiclinking means that bug fixes and upgrades to libraries propagateto improve yourproduct without requiring you to ship anything.
  • Pluginsalways call for dynamiclinking.
  • Staticlinking, means that you can know the code will run in very limited environments(early in the boot process, or in rescue mode).
  • Staticlinking can make binaries easier to distributeto diverse user environments (at the cost of sending a larger and more resource hungry program).
  • Staticlinking may allow slightly faster startuptimes, but this depends to some degree on both the size and complexity of your program andon the details of the OS's loading strategy.
  • 动态链接可以减少总资源消耗(如果多个进程共享同一个库(当然包括“相同”中的版本))。我相信这是促使它在大多数环境中出现的论据。这里的“资源”包括磁盘空间、RAM 和缓存空间。当然,如果您的动态链接器不够灵活,则存在DLL 地狱的风险。
  • 动态链接意味着错误修复和库升级可以传播以改进您的产品,而无需您运送任何东西。
  • 插件总是需要动态链接。
  • 静态链接,意味着您可以知道代码将在非常有限的环境中运行(在启动过程的早期,或在救援模式中)。
  • 静态链接可以使二进制文件更容易分发到不同的用户环境(以发送更大和更多资源的程序为代价)。
  • 静态链接可能允许稍微快一点的启动时间,但这在某种程度上取决于程序的大小和复杂性以及操作系统加载策略的细节。


Some edits to include the very relevant suggestions in the comments and in other answers. I'd like to note that the way you break on this depends a lot on what environment you plan to run in. Minimal embedded systems may not have enough resources to support dynamic linking. Slightly larger small systems may well support dynamic linking, because their memory is small enough to make the RAM savings from dynamic linking very attractive. Full blown consumer PCs have, as Mark notes, enormous resources, and you can probably let the convenience issues drive your thinking on this matter.

一些编辑以在评论和其他答案中包含非常相关的建议。我想指出,您打破这一点的方式在很大程度上取决于您计划运行的环境。最小的嵌入式系统可能没有足够的资源来支持动态链接。稍微大一点的小型系统可能很好地支持动态链接,因为它们的内存小到足以使动态链接节省的 RAM 非常有吸引力。正如马克指出的那样,成熟的消费类 PC 拥有巨大的资源,您可能可以让便利性问题驱动您对此问题的思考。



To address the performance and efficiency issues: it depends.

解决性能和效率问题:这取决于.

Classically, dynamic libraries require a some kind of glue layer which often means double dispatch or an extra layer of indirection in function addressing and can cost a little speed (but is function calling time actually a big part of your running time???).

传统上,动态库需要某种胶水层,这通常意味着函数寻址中的双重调度或额外的间接层,并且可能会降低速度(但函数调用时间实际上是运行时间的重要组成部分吗???)。

However, if you are running multiple processes which all call the same library a lot, you can end up saving cache lines (and thus winning on running performance) when using dynamic linking relative to using static linking. (Unless modern OS's are smart enough to notice identical segments in statically linked binaries. Seems hard, anyone know?)

但是,如果您运行的多个进程都大量调用同一个库,则在使用动态链接相对于使用静态链接时,您最终可以节省缓存行(从而赢得运行性能)。(除非现代操作系统足够聪明,可以注意到静态链接二进制文件中的相同段。看起来很难,有人知道吗?)

Another issue: loading time. You pay loading costs at some point. When you pay this cost depends on how the OS works as well as what linking you use. Maybe you'd rather put off paying it until you know you need it.

另一个问题:加载时间。您在某个时候支付装载费用。您何时支付此费用取决于操作系统的工作方式以及您使用的链接。也许你宁愿推迟支付,直到你知道你需要它。

Note that static-vs-dynamic linking is traditionally notan optimization issue, because they both involve separate compilation down to object files. However, this is not required: a compiler can in principle, "compile" "static libraries" to a digested AST form initially, and "link" them by adding those ASTs to the ones generated for the main code, thus empowering global optimization. None of the systems I use do this, so I can't comment on how well it works.

请注意,静态与动态链接传统上不是优化问题,因为它们都涉及到目标文件的单独编译。但是,这不是必需的:原则上,编译器可以最初将“静态库”“编译”为消化后的 AST 形式,然后通过将这些 AST 添加到为主代码生成的 AST 来“链接”它们,从而实现全局优化。我使用的系统都没有这样做,所以我无法评论它的工作情况。

The way to answer performance questions is alwaysby testing (and use a test environment as much like the deployment environment as possible).

回答性能问题的方法总是通过测试(并尽可能使用与部署环境相似的测试环境)。

回答by Lothar

1) is based on the fact that calling a DLL function is always using an extra indirect jump. Today, this is usually negligible. Inside the DLL there is some more overhead on i386 CPU's, because they can't generate position independent code. On amd64, jumps can be relative to the program counter, so this is a huge improvement.

1) 基于这样一个事实,即调用 DLL 函数总是使用额外的间接跳转。今天,这通常可以忽略不计。在 DLL 内部,i386 CPU 的开销更大,因为它们无法生成位置无关代码。在 amd64 上,跳转可以相对于程序计数器,所以这是一个巨大的改进。

2) This is correct. With optimizations guided by profiling you can usually win about 10-15 percent performance. Now that CPU speed has reached its limits it might be worth doing it.

2)这是正确的。通过分析指导的优化,您通常可以获得大约 10-15% 的性能。现在 CPU 速度已达到极限,可能值得这样做。

I would add: (3) the linker can arrange functions in a more cache efficient grouping, so that expensive cache level misses are minimised. It also might especially effect the startup time of applications (based on results i have seen with the Sun C++ compiler)

我要补充的是:(3) 链接器可以将函数安排在一个更高效的缓存分组中,从而最大限度地减少昂贵的缓存级别未命中。它也可能特别影响应用程序的启动时间(基于我使用 Sun C++ 编译器看到的结果)

And don't forget that with DLLs no dead code elimination can be performed. Depending on the language, the DLL code might not be optimal either. Virtual functions are always virtual because the compiler doesn't know whether a client is overwriting it.

并且不要忘记,使用 DLL 无法消除死代码。根据语言的不同,DLL 代码也可能不是最佳的。虚函数始终是虚函数,因为编译器不知道客户端是否正在覆盖它。

For these reasons, in case there is no real need for DLLs, then just use static compilation.

由于这些原因,如果真的不需要 DLL,那么只需使用静态编译。

EDIT (to answer the comment, by user underscore)

编辑(回答评论,由用户下划线)

Here is a good resource about the position independent code problem http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

这是一个关于位置无关代码问题的好资源http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

As explained x86 does not have them AFAIK for anything else then 15 bit jump ranges and not for unconditional jumps and calls. That's why functions (from generators) having more then 32K have always been a problem and needed embedded trampolines.

正如所解释的,x86 没有 AFAIK 用于其他任何东西,然后是 15 位跳转范围,而不是用于无条件跳转和调用。这就是为什么具有超过 32K 的函数(来自生成器)一直是一个问题并且需要嵌入式蹦床的原因。

But on popular x86 OS like Linux you do not need to care if the .so/DLL file is not generated with the gccswitch -fpic(which enforces the use of the indirect jump tables). Because if you don't, the code is just fixed like a normal linker would relocate it. But while doing this it makes the code segment non shareable and it would need a full mapping of the code from disk into memory and touching it all before it can be used (emptying most of the caches, hitting TLBs) etc. There was a time when this was considered slow.

但是在像 Linux 这样流行的 x86 操作系统上,您不需要关心 .so/DLL 文件是否不是通过gcc开关生成的-fpic(强制使用间接跳转表)。因为如果你不这样做,代码就像一个普通的链接器会重新定位它一样被修复。但是在这样做时,它会使代码段不可共享,并且需要将代码从磁盘完整映射到内存并在使用之前将其全部接触(清空大部分缓存,命中 TLB)等。 曾经有一段时间当这被认为是缓慢的。

So you would not have any benefit anymore.

这样你就不会再有任何好处了。

I do not recall what OS (Solaris or FreeBSD) gave me problems with my Unix build system because I just wasn't doing this and wondered why it crashed until I applied -fPICto gcc.

我不记得什么操作系统(Solaris或FreeBSD的)给我的问题,我的Unix编译系统,因为我只是不这样做的,不知道为什么它坠毁,直到应用我-fPICgcc

回答by Mark Ransom

Dynamic linking is the only practical way to meet some license requirements such as the LGPL.

动态链接是满足某些许可要求(例如LGPL)的唯一实用方法。

回答by stakx - no longer contributing

I agree with the points dnmckee mentions, plus:

我同意 dnmckee 提到的观点,另外:

  • Statically linked applications might be easier to deploy, since there are fewer or no additional file dependencies (.dll / .so) that might cause problems when they're missing or installed in the wrong place.
  • 静态链接的应用程序可能更容易部署,因为当它们丢失或安装在错误的位置时可能会导致问题的附加文件依赖项(.dll / .so)较少或没有。

回答by Rob Wells

One reason to do a statically linked build is to verify that you have full closure for the executable, i.e. that all symbol references are resolved correctly.

进行静态链接构建的原因之一是验证您对可执行文件已完全关闭,即所有符号引用都已正确解析。

As a part of a large system that was being built and tested using continuous integration, the nightly regression tests were run using a statically linked version of the executables. Occasionally, we would see that a symbol would not resolve and the static link would fail even though the dynamically linked executable would link successfully.

作为使用持续集成构建和测试的大型系统的一部分,夜间回归测试使用可执行文件的静态链接版本运行。有时,我们会看到符号无法解析并且静态链接将失败,即使动态链接的可执行文件链接成功。

This was usually occurring when symbols that were deep seated within the shared libs had a misspelt name and so would not statically link. The dynamic linker does not completely resolve all symbols, irrespective of using depth-first or breadth-first evaluation, so you can finish up with a dynamically linked executable that does not have full closure.

这通常发生在位于共享库中的符号的名称拼写错误时,因此不会静态链接。无论使用深度优先还是广度优先评估,动态链接器都不会完全解析所有符号,因此您可以完成一个没有完全闭包的动态链接可执行文件。

回答by AProgrammer

1/ I've been on projects where dynamic linking vs static linking was benchmarked and the difference wasn't determined small enough to switch to dynamic linking (I wasn't part of the test, I just know the conclusion)

1/ 我一直在对动态链接与静态链接进行基准测试的项目中,差异没有确定到足以切换到动态链接(我不是测试的一部分,我只知道结论)

2/ Dynamic linking is often associated with PIC (Position Independent Code, code which doesn't need to be modified depending on the address at which it is loaded). Depending on the architecture PIC may bring another slowdown but is needed in order to get benefit of sharing a dynamically linked library between two executable (and even two process of the same executable if the OS use randomization of load address as a security measure). I'm not sure that all OS allow to separate the two concepts, but Solaris and Linux do and ISTR that HP-UX does as well.

2/ 动态链接通常与PIC(位置无关代码,不需要根据加载地址进行修改的代码)相关联。根据架构,PIC 可能会带来另一次减速,但为了获得在两个可执行文件之间共享动态链接库的好处(如果操作系统使用加载地址随机化作为安全措施,甚至同一可执行文件的两个进程),则需要这样做。我不确定所有操作系统都允许将这两个概念分开,但 Solaris 和 Linux 这样做,而 HP-UX 也这样做。

3/ I've been on other projects which used dynamic linking for the "easy patch" feature. But this "easy patch" makes the distribution of small fix a little easier and of complicated one a versioning nightmare. We often ended up by having to push everything plus having to track problems at customer site because the wrong version was token.

3/ 我一直在其他项目中使用动态链接来实现“简单补丁”功能。但是这个“简单的补丁”使小补丁的分发变得更容易一些,而复杂的补丁则是版本控制的噩梦。我们经常最终不得不推送所有内容,并且不得不在客户站点跟踪问题,因为错误的版本是令牌。

My conclusion is that I'd used static linking excepted:

我的结论是,我使用了静态链接除外:

  • for things like plugins which depend on dynamic linking

  • when sharing is important (big libraries used by multiple processes at the same time like C/C++ runtime, GUI libraries, ... which often are managed independently and for which the ABI is strictly defined)

  • 对于依赖动态链接的插件之类的东西

  • 当共享很重要时(多个进程同时使用的大型库,如 C/C++ 运行时、GUI 库……它们通常是独立管理的,并且 ABI 是严格定义的)

If one want to use the "easy patch", I'd argue that the libraries have to be managed like the big libraries above: they must be nearly independent with a defined ABI that must not to be changed by fixes.

如果有人想使用“简单补丁”,我认为必须像上面的大库一样管理这些库:它们必须几乎独立于定义的 ABI,并且不能被修复程序更改。

回答by nos

Thisdiscuss in great detail about shared libraries on linux and performance implications.

这将详细讨论 linux 上的共享库和性能影响。

回答by Jonathan Leffler

On Unix-like systems, dynamic linking can make life difficult for 'root' to use an application with the shared libraries installed in out-of-the-way locations. This is because the dynamic linker generally won't pay attention to LD_LIBRARY_PATH or its equivalent for processes with root privileges. Sometimes, then, static linking saves the day.

在类 Unix 系统上,动态链接会使“root”难以使用共享库安装在偏远位置的应用程序。这是因为动态链接器通常不会注意 LD_LIBRARY_PATH 或其对具有 root 权限的进程的等效项。有时,静态链接可以节省一天的时间。

Alternatively, the installation process has to locate the libraries, but that can make it difficult for multiple versions of the software to coexist on the machine.

或者,安装过程必须定位库,但这会使多个版本的软件难以在机器上共存。

回答by Hans Passant

It is pretty simple, really. When you make a change in your source code, do you want to wait 10 minutes for it to build or 20 seconds? Twenty seconds is all I can put up with. Beyond that, I either get out the sword or start thinking about how I can use separate compilation and linking to bring it back into the comfort zone.

这很简单,真的。当您对源代码进行更改时,您希望等待 10 分钟来构建它还是等待 20 秒?二十秒是我所能忍受的。除此之外,我要么放弃剑,要么开始考虑如何使用单独的编译和链接将其带回舒适区。

回答by Arne

Best example for dynamic linking is, when the library is dependent on the used hardware. In ancient times the C math library was decided to be dynamic, so that each platform can use all processor capabilities to optimize it.

动态链接的最佳示例是,当库依赖于使用的硬件时。在古代,C 数学库被决定为动态的,以便每个平台都可以使用所有处理器功能来优化它。

An even better example might be OpenGL. OpenGl is an API that is implemented differently by AMD and NVidia. And you are not able to use an NVidia implementation on an AMD card, because the hardware is different. You cannot link OpenGL statically into your program, because of that. Dynamic linking is used here to let the API be optimized for all platforms.

一个更好的例子可能是 OpenGL。OpenGl 是一种由 AMD 和 NVidia 以不同方式实现的 API。而且您不能在 AMD 卡上使用 NVidia 实现,因为硬件不同。因此,您不能将 OpenGL 静态链接到您的程序中。这里使用动态链接让 API 针对所有平台进行优化。