2

在我正在开发的嵌入式设备上,启动时间是一个重要问题。整个应用程序由几个使用一组库的可执行文件组成。因为闪存中的空间有限,我们想使用共享库。

该应用程序在编译并与共享库链接时照常工作,并且闪存量按预期减少。与链接到静态库的版本不同的是,应用程序的启动时间长了大约 20 秒,我不知道为什么。

该应用程序在 180 MHz 的 ARM9 CPU 上运行,带有 Linux 2.6.17 操作系统、16 MB 闪存(JFFS 文件系统)和 32 MB RAM。

4

6 回答 6

7

因为共享库必须在运行时链接到,通常通过 dlopen() 或类似的东西。静态库没有这样的步骤。

编辑:更多细节。dlopen 必须执行以下任务。

  • 查找共享库
  • 将其加载到内存中
  • 递归加载所有依赖项(及其依赖项......)
  • 解决所有符号

这需要相当多的 IO 操作才能完成。

在静态链接的程序中,以上所有内容都是在编译时完成的,而不是运行时。因此加载静态链接程序要快得多。

在您的情况下,您的代码必须运行的相对较慢的硬件夸大了差异。

于 2009-09-11T12:58:01.813 回答
4

这是速度和空间的经典权衡的一个很好的例子。

您可以静态链接所有可执行文件,以便它们更快,但它们会占用更多空间

或者

您可以拥有占用更少空间但加载时间更长的共享库。

所以决定你想牺牲什么。

这种差异有很多因素(操作系统、编译器等),但可以在此处找到一个很好的原因列表。基本上共享库是出于空间原因而创建的,并且使它们工作所涉及的许多“魔术”都会影响性能。

(作为历史记录,Linux/Unix 上的原始 Netscape 导航器是一个静态链接的大胖可执行文件)。

于 2009-09-11T13:08:33.043 回答
2

这可能会帮助其他有类似问题的人:

就我而言,启动需要这么长时间的原因是,GCC 的默认设置是导出库中的所有符号。一个很大的改进是设置编译器设置“-fvisibility=hidden”。

lib 必须导出的所有符号都必须使用语句进行扩充

__attribute__ ((visibility("default")))

请参阅gcc wiki
和非常好的文章如何编写共享库

于 2009-10-22T15:16:59.473 回答
1

好的,我现在了解到共享库的使用在速度方面存在缺点。我发现这篇关于动态链接和加载启发的文章。加载过程似乎比我预期的要长得多。

于 2009-09-11T13:27:37.220 回答
0

One option which seems obvious to me, is to statically link the several programs all into a single binary. That way you continue to share as much code as possible (probably more than before), but you will also avoid the overhead of the dynamic linker AND save the space of having the dynamic linker on the system at all.

It's pretty easy to combine several executables into the same one, you normally just examine argv and decide which routine to call based on that.

于 2009-09-11T21:15:12.983 回答
0

有趣.. 从静态链接的胖应用程序中,共享库的加载时间通常是不明显的。所以我只能推测系统要么从闪存加载库非常慢,要么正在以某种方式检查加载的库(例如.NET应用程序对所有加载的dll运行校验和,从而大大减少了启动时间一些案例)。可能是共享库正在按需加载,然后卸载,这可能表明存在配置问题。

所以,对不起,我不知道为什么,但我认为这是你的 ARM 设备/操作系统的问题。您是否尝试过检测启动代码,或静态链接 1 个最常用的库,看看是否有很大的不同。还将共享库与应用程序放在同一目录中,以减少在 FS 中搜索库所需的时间。

于 2009-09-11T13:21:36.643 回答