为什么在使用共享库时,Linux上的App启动速度较慢?

时间:2009-09-11 12:54:22

标签: linux shared-libraries startup

在我正在研究的嵌入式设备上,启动时间是一个重要问题。整个应用程序由几个使用一组库的可执行文件组成。由于FLASH内存空间有限,我们希望使用共享库。

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

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

6 个答案:

答案 0 :(得分:7)

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

编辑:更详细一些。 dlopen必须执行以下任务。

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

这需要完成很多IO操作。

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

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

答案 1 :(得分:4)

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

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

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

所以决定你要牺牲什么。

这种差异有许多因素(OS,编译器e.t.c),但可以找到一个很好的理由列表here。基本上共享库是出于空间原因而创建的,并且使它们工作所涉及的大部分“魔法”都会受到性能影响。

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

答案 2 :(得分:2)

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

在我的情况下启动花了这么长时间的原因是,GCC的默认设置是导出库中的所有符号。 一个很大的改进是设置编译器设置“-fvisibility = hidden”。

必须使用语句

扩充lib必须导出的所有符号

__attribute__ ((visibility("default")))

gcc wiki
和非常好的文章how to write shared libraries

答案 3 :(得分:1)

好的,我现在已经了解到共享库的使用对速度有不利影响。我发现这篇关于dynamic linking and loading启发的文章。装载过程似乎比我预期的要长得多。

答案 4 :(得分:0)

有趣的..通常,共享库的加载时间与静态链接的胖应用程序无法察觉。所以我只能猜测系统要么从闪存加载库要么很慢,要么以某种方式检查加载的库(例如.NET应用程序为所有加载的dll运行校验和,大大减少启动时间)一些案例)。可能是根据需要加载共享库,然后卸载,这可能表示配置问题。

所以,抱歉,我不禁说出原因,但我认为这是您的ARM设备/操作系统的问题。您是否尝试过检测启动代码,或者静态链接1个最常用的库,看看是否会产生很大的差异。还将共享库放在与应用程序相同的目录中,以减少搜索FS的库所需的时间。

答案 5 :(得分:0)

对我来说,一个显而易见的选择是将几个程序静态链接到一个二进制文件中。这样你就可以继续共享尽可能多的代码(可能比以前更多),但你也可以避免动态链接器的开销,并节省在系统上拥有动态链接器的空间。

将几个可执行文件组合到同一个可执行文件中非常容易,通常只需检查argv并根据该文件决定调用哪个例程。