静态与动态库性能
人们普遍认为静态库的性能优于动态库。我的问题是:它是否还取决于 dll 是否已加载到内存中?我的意思是,一旦初始化和所有事情都发生了,动态库的函数调用和执行是否比静态库花费更长的时间?
It's a general notion that performance of static libraries is greater than that of dynamic. My question is: does it also depend on once the dll is already loaded in memory? I mean, once the initialization and all has happened, does the function calling and execution take longer in case of dynamic libraries than static libraries?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
免责声明:我是一名 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。无论如何,进程启动时间的影响与延迟加载加载时动态链接的影响相同;然而,每个方法调用上的指针取消引用确实会增加一个可以忽略不计的小成本。 (尽管如果您知道自己在做什么,您可能会疯狂地修复进程内存以避免指针取消引用。但是,正确执行此操作的努力比您将获得的性能收益大一个数量级它。)
Disclaimer: I am a Linux-fu grasshopper, so there might be some inaccuracies here and there (or just everywhere). But the general idea should be relatively correct.Sort of. And if it's not, I am sure the good SO people will quickly correct me. :-)
Oh, and the links I provided are Windows-centric. I would appreciate if anyone can provide the proper Linux-centric links.
Short answer: It might. However, even if it does, the performance difference is really negligible.
When you link a static library, the compiler generates the code to do all function calls directly. When the process is created, and that code is executed, the function call is a simple call instruction.
When you use a dynamic library, the cost depends on whether you are using load-time dynamic linking or run-time dynamic linking.
With load-time dynamic linking, the compiler still generates code to call the function directly, as if it's a statically linked. When the process loader loads the DLL, it'll invoke the runtime linker to fix the process memory, so that those calls go directly to the actual function implementations. This has to happen before any call to a function from the loaded library is made. on Windows, it's done by the NT DLL loader, which calls LoadLibrary on the DLL at process initialization time. On Linux, it's done by the runtime linker, ld-linux.so.
With
/DELAYLOAD
load-time dynamic linking, the process is esentially the same, except the compiler generates code to call small stubs, which will check if the library is loaded, and if not, will call the NT DLL loader. Thus, the DLL will be loaded on demand, and the process loader doesn't have to load it at process initialization time. This results in faster process startup time, but the call performance is still the same. (Note however, that delay load suffers from other drawbacks)I don't know if there's a corresponding Linux support, but I would be surprised if there isn't.
With run-time dynamic linking, your code maintains the function pointers and decides when to dload the library. On Windows, it has to use LoadLibrary and GetProcAddress, on Linux it's dlopen, dlsym and dlclose. In any case, the implications for the process startup time are the same as for the delay-load load-time dynamic linking; however, the pointer dereferencing on each method call does add a small negligible cost. (Although if you know what you are doing, you could go crazy and fix-up your process memory to avoid the pointer dereferencing. The effort to do this right however is an order of magnitude bigger than the perf benefits you'll get for doing it.)
我认为在性能方面最大的区别是,使用静态库,编译器可以优化对库的函数调用,但在动态库中,编译器对它所调用的函数的行为一无所知。
I think the biggest difference, performance-wise, is that with a static library the compiler can optimize function calls to the library, but in a dynamic one the compiler knows nothing about the behaviour of the function it is calling.
DLL 或静态库中的机器代码本身具有相同的性能。不过,编译器可以更积极地优化具有静态库的可执行文件,尤其是在打开链接时代码生成时。人们可以考虑删除未使用的变量和重复代码,并在一起使用时将代码放置在彼此靠近的位置(请参阅 PGO)。
当代码在应用程序之间共享时,从系统性能的角度来看,最好使用 DLL,因为系统的整体内存压力较小(当操作系统能够跨进程映射内存部分的视图时, Windows 确实如此)。
The machine code itself in a DLL or static library have ofc the same performance. A compiler can though more aggressively optimize an executable with static libraries, especially when link-time code generation is turned on. One can think of removal of unused variables and duplicate code and placement of code close to each other when used together (see PGO).
When code is shared across applications it's better to use DLL's from a system performance point of view, since the overall memory pressure of the system is less (when os is able to map views of memory sections across processes which Windows does).