8

我有一个关于共享库与静态库加载时间的问题。

假设我有一个使用 liba、libb、libc 的可执行文件 foo.exe。同样在给定时间,机器上运行的可执行文件实例超过 10 个。

现在,如果上述 3 个库是共享库:第一个实例被加载到 RAM 中:所用时间将是 foo.exe 的 main() 加载内存所用的时间(假设它可以忽略不计)+ 加载 liba 的时间 + 加载时间libb + time to load libc 2nd instance is started : 现在假设这个可执行文件的第二个实例正在运行。由于所有库都已加载到主内存中,因此仅将 main() 加载到内存中所花费的时间可以忽略不计。

现在,如果上述 3 个库是静态库:第一个实例被加载到 RAM 中:所花费的时间将是 foo.exe 的 main() 加载内存所花费的时间(假设它可以忽略不计)+ 加载 liba 的时间 + 加载时间libb + 加载 libc 的时间(当然,它现在是整个可执行文件的所有部分)第二个实例已启动:现在假设该可执行文件的第二个实例正在运行。所用时间将再次是 foo.exe 的 main() 加载内存所用的时间(假设它可以忽略不计)+ 加载 liba 的时间 + 加载 libb 的时间 + 加载 libc 的时间。(因为每个可执行文件都不能共享库,因为它们是静态库)

所以我的结论是,使用静态库加载时间会更长。但有人告诉我,共享库在加载过程中比静态库需要更多时间,所以会有延迟,所以共享库不是一个好的选择。这怎么可能 ?

4

3 回答 3

10

链接(解析引用)不是免费的。使用静态链接,在生成二进制文件时就可以一劳永逸地完成解析。使用动态链接,每次加载二进制文件时都必须这样做。更不用说编译为在共享库中运行的代码可能比编译为静态链接的代码效率低。确切的成本取决于架构和系统的动态链接实现。

对于 32 位 x86 指令集,使库动态化的成本可能相对较高:在ELF 二进制格式中,必须牺牲一个已经稀缺的寄存器来使动态链接的代码可重定位。旧的a.out格式将每个共享库放置在一个固定的位置,但这并没有扩展。我相信当动态库放置在地址空间中的预定位置时,Mac OS X 有一个中间系统,但是冲突在单个计算机的规模上得到了解决(安装新系统后的漫长的“优化系统性能”阶段)软件)。在某种程度上,这个系统(称为预绑定) 让您拥有蛋糕并吃掉它。我不知道现在 Apple 几乎切换到 amd64 架构后是否还需要预绑定。

此外,在现代操作系统上,静态和动态链接的代码仅在使用时才从磁盘加载(分页),但这与您的问题完全正交。

于 2010-01-08T04:21:06.753 回答
2

静态库在编译时链接,共享库在运行时链接。因此,使用静态库的可执行文件甚至在写入磁盘之前就摊销了所有链接时间。

于 2010-01-08T04:17:31.613 回答
0

非常感谢这个令人难以置信的快速响应。我们有 2 个架构场景:

Q1。架构 1:假设 exe 大小为 3GB(静态库)。95% 是库,5% 是 main()。如此庞大的大小将加载此 exe 需要更多时间(假设静态库)或链接此 exe 需要更多时间(假设使用共享库,并且如果所有库都已经在内存中只需要进行链接。)

Architecure-2:假设我的 exe 大小为 1.5GB(95% lib + 5% main()),并且同时运行 6 个实例。一旦这 6 个实例启动,它们将运行数天,假设我们已准备好在这 6 个实例的初始加载+链接期间承受额外的延迟。

Q2。现在,如果我使用共享对象而不是静态对象,由于所有库都在 6 个实例之间共享,我会在 RAM 上有很多可用空间吗?由于 RAM 中有更多空间会减少页面交换,我的实时执行速度会不会加快?

Q3。如果我使用“映射”文件来减少导出的符号数量(这只能使用共享库),我的符号表大小不会减小,并且不会提高运行时性能吗?

谢谢苏德

于 2010-01-08T05:22:16.193 回答