静态与dynamic库性能

这是一代人的观点,静态libarries的性能比dynamic性能更快。 我的问题是,这是否也取决于一旦dll被加载到内存中。 我的意思是,一旦初始化和所有的事情发生,dynamic库的情况下调用和执行花费的时间比静态库更长。

免责声明 :我是一个Linux-fu蚱蜢,所以在这里或那里(或者到处都是)可能会有一些不准确的地方。 但总体思路应该是比较正确的。 如果不是的话,我肯定好的人会很快纠正我的。 🙂

哦,我提供的链接是以Windows为中心的。 如果有人能提供适当的以Linux为中心的链接,我将不胜感激。

简答:可能。 但是,即使这样做,性能差异也是微不足道的。

链接静态库时,编译器会生成代码以直接执行所有函数调用。 当进程被创建并且代码被执行时,函数调用是一个简单的调用指令。

在使用动态库时,成本取决于您是使用加载时动态链接还是运行时动态链接

使用加载时动态链接 ,编译器仍然生成直接调用该函数的代码,就好像它是一个静态链接。 当进程加载器加载DLL时,它将调用运行时链接器来修复进程内存,以便这些调用直接进入实际的函数实现。 在从加载的库中调用函数之前,必须发生这种情况。 在Windows上,它由NT DLL加载器完成,它在进程初始化时调用DLL上的LoadLibrary。 在Linux上,它由运行时链接程序ld-linux.so完成。

使用/DELAYLOAD 加载时动态链接 ,这个过程基本上是一样的,除了编译器生成代码来调用小的存根,这将检查库是否加载,如果没有,将调用NT DLL加载器。 因此,DLL将按需加载,并且进程加载器不必在进程初始化时加载它。 这导致更快的流程启动时间,但通话性能仍然相同。 (但是请注意,延迟负载存在其他缺点)

我不知道是否有相应的Linux支持,但如果没有,我会感到惊讶。

通过运行时动态链接 ,代码将维护函数指针并决定何时装入库。 在Windows上,它必须使用LoadLibrary和GetProcAddress,在Linux上它是dlopen,dlsym和dlclose。 在任何情况下,对进程启动时间的影响与对延迟加载加载时间动态链接的影响相同 ; 然而,每个方法调用的指针解引用确实增加了一个微不足道的成本。 (虽然如果你知道自己在做什么,你可能会发疯,并修复你的进程内存,以避免指针取消引用。然而,这样做的努力是比你获得的性能好一个数量级它。)

我认为最大的区别在于性能方面,使用静态库时,编译器可以优化对库的函数调用,但是在动态的编译器中,编译器对它所调用的函数的行为一无所知。

机器码本身在DLL或静态库中具有相同的性能。 编译器可以更积极地使用静态库优化可执行文件,特别是在启用链接时生成代码时。 人们可以考虑删除未使用的变量,并且在一起使用时重复代码和代码的位置(见PGO)。

当跨应用程序共享代码时,从系统性能的角度来看,最好使用DLL,因为系统的整体内存压力较小(当OS能够映射跨Windows进程的内存部分的视图时)。