1)通常情况下,静态链接和动态链接之间的运行时性能差异微不足道。
2)如果使用利用档案数据来优化程序热点路径的 profiling 编译器,(1)不成立,因为在静态链接中,编译器可以优化您的代码和库代码。而使用动态链接仅可以优化您的代码。如果大部分时间花费在运行库代码上,这可能会产生很大的影响。否则,(1)仍然适用。
一些编辑,包括评论和其他答案中非常相关的建议。需要注意的是,你在此方面的断点方式很大程度上取决于你计划运行的环境。最小的嵌入式系统可能没有足够的资源支持动态链接。稍大一些的小型系统可能会支持动态链接,因为它们的内存足够小,使动态链接的RAM节省非常有吸引力。完整的消费级PC具有巨大的资源,正如马克指出,你可能可以让便利问题来推动你对这个问题的思考。
1) 基于一个事实,调用DLL函数总是会使用额外的间接跳转。今天,这通常可以忽略不计。在DLL内部,i386 CPU上有更多的开销,因为它们无法生成位置无关代码。在amd64上,跳转可以相对于程序计数器,这是一个巨大的改进。
2) 这是正确的。通过优化来自性能分析的指导,您通常可以获得10-15%的性能提升。现在CPU速度已经达到极限,这可能值得一试。
我想补充一点:(3)链接器可以将函数排列在更高效的缓存分组中,以使昂贵的缓存级别失误最小化。它也可能特别影响应用程序的启动时间(基于我用Sun C ++编译器看到的结果)
而且不要忘记,对于DLLs,无法执行死代码消除。根据语言,DLL代码可能也不是最优的。虚拟函数始终是虚拟的,因为编译器不知道客户端是否正在覆盖它。
出于这些原因,如果没有真正需要DLL,则只需使用静态编译。
编辑(回答用户underscore的评论)
这里有一个关于位置无关代码问题的好资源http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/
如已解释,x86除了15位跳跃范围外,似乎没有其他用途,并且不适用于无条件跳转和调用。这就是为什么拥有超过32K的函数(从生成器中)一直是个问题并需要嵌入式跳板。
但是在像Linux这样的流行x86操作系统上,您不需要担心.so/DLL文件是否使用gcc
开关-fpic
生成(该开关强制使用间接跳转表)。因为如果您不这样做,代码就像普通链接器一样被修复。但是在执行此操作时,它会使代码段无法共享,并且需要将代码从磁盘完全映射到内存中并触摸所有内容,然后才能使用它(清空大部分缓存,命中TLB等)。有一段时间,这被认为很慢。
因此,您将不再获得任何好处。
我不记得我的Unix构建系统在哪个操作系统(Solaris或FreeBSD)上给我带来了问题,因为我没有这样做,直到我向gcc
应用了-fPIC
,才想到为什么会崩溃。
动态链接是满足某些许可证要求的唯一实用方式,例如LGPL。
我同意dnmckee提到的观点,另外还有:
进行静态链接的一个原因是为了验证可执行文件的完全封闭性,即所有符号引用都被正确解析。
在使用持续集成构建和测试的大型系统中,每晚的回归测试都是使用静态链接版本的可执行文件运行。偶尔会发现一个符号无法解析,导致静态链接失败,尽管动态链接的可执行文件能够成功链接。
通常情况下,这种情况发生的原因是共享库中深层嵌套的符号名称拼写错误,因此无法静态链接。动态链接器无论使用深度优先还是广度优先评估,都无法完全解析所有符号,因此您可能会得到一个没有完全封闭性的动态链接的可执行文件。
1/ 我曾参与过一些项目,对动态链接和静态链接进行了基准测试,结果发现两者之间的差异不足以使我们转向使用动态链接(我没有参与测试,只是知道结论)。
2/ 动态链接通常与PIC(位置无关代码)相关联,它是一种不需要根据加载地址进行修改的代码。根据体系结构的不同,PIC可能会带来额外的性能下降,但是为了共享动态链接库的好处是必需的,这适用于两个可执行文件之间甚至是同一可执行文件的两个进程(如果操作系统将加载地址随机化作为安全措施)。我不确定所有操作系统是否允许分离这两个概念,但Solaris和Linux可以,我记得HP-UX也可以。
3/ 我曾参与过其他项目,其中使用动态链接来实现“轻松补丁”功能。但是这种“轻松补丁”会使小修复的分发变得更加容易,而复杂修复的版本控制则会变成噩梦。我们经常不得不推出所有东西,而且还要在客户现场跟踪问题,因为使用了错误的版本。
我的结论是,我会使用静态链接,除非:
像依赖于动态链接的插件之类的东西
共享很重要(由多个进程同时使用的大型库,例如C/C++运行时库、GUI库等,通常是独立管理的,并且ABI严格定义)
如果要使用“轻松补丁”,我认为库必须像上述大型库那样进行管理:它们必须几乎是独立的,并具有不应通过修复而更改的定义良好的ABI。
静态链接
是在编译时将链接内容复制到主二进制文件中,形成一个单一的二进制文件。
缺点:
动态链接
是在运行时加载链接的内容。该技术允许:
ABI
稳定性[相关]缺点:
其实很简单。当您在源代码中进行更改时,您想等待10分钟才能构建完成还是20秒钟?我只能容忍20秒钟的时间。超过这个时间,我要么找出解决方案,要么考虑如何使用分离编译和链接来使它回到舒适区。
动态链接的最佳例子是,当库依赖于使用的硬件时。在古代,决定C数学库是动态的,这样每个平台都可以利用所有处理器功能来优化它。
甚至更好的例子可能是OpenGL。OpenGL是一个由AMD和NVidia不同实现的API。您无法在AMD卡上使用NVidia实现,因为硬件不同。你不能将OpenGL静态链接到你的程序中,因为这个原因。动态链接在这里被用来让API为所有平台进行优化。