静态链接与动态链接
在某些情况下,是否有任何令人信服的性能原因来选择通过动态链接进行静态链接,反之亦然? 我听过或读过以下内容,但我对这个主题不太了解,不能保证其准确性。
1)静态链接和动态链接之间的运行时性能差异通常可以忽略不计。
2)(1)如果使用分析编译器使用概要文件数据优化程序热路径,因为使用静态链接,编译器可以优化代码和库代码。 通过动态链接,只有您的代码可以被优化。 如果大部分时间用于运行库代码,这可能会产生很大的差异。 否则,(1)仍然适用。
一些编辑在评论和其他答案中包含非常相关的建议。 我想指出的是,你打破这种方式很大程度上取决于你计划运行的环境。最小的嵌入式系统可能没有足够的资源来支持动态链接。 稍微大一些的小型系统可以很好地支持链接,因为它们的内存足够小,使得从动态链接节省内存非常有吸引力。 正如马克指出的,成熟的消费者个人电脑具有巨大的资源,您可能会因便利问题而促使您思考这个问题。
解决性能和效率问题: 这取决于 。
通常情况下,动态库需要某种粘合层,这通常意味着在函数寻址中双重调度或额外的间接层,并且可能花费一点速度(但功能调用时间实际上是您运行时间的很大一部分?)。
但是,如果运行多个进程都会调用同一个库,那么在使用静态链接相对使用动态链接时,最终可能会保存缓存行(从而赢得运行性能)。 (除非现代操作系统足够聪明才能注意到静态链接二进制文件中的相同段。似乎很难,任何人都知道?)
另一个问题:加载时间。 您在某个时间支付加载成本。 当你支付这笔费用取决于操作系统的工作方式以及你使用的链接。 也许你宁愿拖延付款,直到你知道你需要它。
请注意,静态与动态链接传统上不是优化问题,因为它们都涉及单独编译到对象文件。 然而,这不是必需的:编译器原则上可以最初将“静态库”“编译”为最初消化的AST形式,并通过将这些AST添加到为主代码生成的AST中来“链接”它们,从而实现全局优化。 我使用的系统都没有这样做,所以我无法评论它的工作效果。
回答性能问题的方法总是通过测试(并尽可能像使用部署环境一样使用测试环境)。
动态链接是满足某些许可要求(如LGPL)的唯一实用方法。
1)基于调用DLL函数的事实总是使用额外的间接跳转。 今天,这通常可以忽略不计。 在DLL内部,i386 CPU的开销更大,因为它们不能生成位置无关的代码。 在amd64上,跳转可以相对于程序计数器,所以这是一个巨大的改进。
2)这是正确的。 通过分析指导进行优化,通常可以赢得10-15%的性能。 现在CPU速度已经达到了极限,这可能是值得的。
我会补充一下:(3)链接器可以以更高效的缓存分组来安排功能,以便将昂贵的缓存失误降至最低。 它也可能会影响应用程序的启动时间(基于我在Sun C ++编译器中看到的结果)
并且不要忘记,使用DLL的时候,不需要执行死代码。 根据不同的语言,DLL代码可能不是最佳的。 虚拟函数总是虚拟的,因为编译器不知道客户端是否覆盖它。
由于这些原因,如果没有真正的DLL需求,那么就使用静态编译。
编辑(通过用户下划线回答评论)
这是一个关于位置独立代码问题的好资源http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/
正如所解释的,x86没有AFAIK,所以没有15位跳转范围,也没有用于无条件跳转和调用。 这就是为什么具有32K以上的功能(来自发电机)一直是个问题,需要嵌入蹦床。
但在像Linux这样流行的x86操作系统上,如果SO / DLL文件不是使用gcc
开关-fpic
(强制使用间接跳转表)生成的,则不需要关心。 因为如果你不这样做,那么代码就像正常的链接器那样被修复就可以重新定位它。 但是,这样做会使代码段不可共享,并且需要将代码从磁盘完全映射到内存中,并在它可以使用之前将其全部触及(清空大部分缓存,打击TLB)等等。有时候当这被认为是慢...太慢。
所以你不会再有任何好处了。
我不记得OS(Solaris或FreeBSD)给我的Unix gcc
系统带来了什么问题,因为我只是没有这样做,并且想知道为什么它会崩溃,直到我将-fPIC
应用于gcc
。
上一篇: Static linking vs dynamic linking
下一篇: Storing different object as void* and casting from and to void*