2009-09-11 75 views
1

在我正在开发的嵌入式设备上,启动时间是一个重要问题。整个应用程序由多个使用一组库的可执行文件组成。由于FLASH存储空间有限,我们希望使用共享库。为什么使用共享库时,Linux上的应用程序启动较慢?

应用程序像往常一样编译并链接到共享库,并且闪存的数量按预期减少。 与链接到静态库的版本的区别在于应用程序的启动时间长了大约20秒,我不知道为什么。

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

回答

7

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

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

  • 找到共享库的
  • 加载到内存中
  • 递归加载所有的依赖关系(和它们的依赖....)
  • 解决所有的符号

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

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

在你的情况下,差异被相对较慢的硬件代码运行所夸大。

+0

@格伦来扩充:你真的认为, dl_open()调用需要很长时间吗?作为交换,启动速度应该更快一点,因为更少的代码需要加载 – chrmue 2009-09-11 13:02:16

+0

@chrmue是的,它可以。必须加载相同数量的代码,但是dlopen有额外的开销。如果你的应用的两个版本之间的唯一区别是静态v的共享库,那么是的,我期望看到共享版本需要更长的时间才能加载。 – Glen 2009-09-11 13:13:09

+0

您可能可以通过预加载来消除一些性能损失。 http://sourceforge.net/projects/preload/ – supercheetah 2009-10-26 17:43:59

4

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

您可以将所有可执行文件静态链接,使他们更快,但随后他们将采取更多的空间

OR

可以有共同的是需要更少的空间,但也有更多的时间来加载库。

因此,决定你想要牺牲什么。

这个差异有很多因素(OS,编译器e.t.c),但可以找到一个很好的原因列表here。基本上共享库是为了空间原因而创建的,大部分涉及到的“魔法”使它们工作都会带来性能问题。 (作为历史记录,Linux/Unix上的原始Netscape导航器是一个静态链接的大型可执行文件)。

+0

@kazanaki:好的,但为什么这么慢,必须有解释? – chrmue 2009-09-11 13:11:32

+0

请注意,如果您使用静态链接,则牺牲的不仅仅是空间。您还牺牲了通过更新库来自动更新您的应用程序的能力。 – 2009-09-11 14:24:29

+0

他们“占用更多空间”的评论具有误导性。如果你有一个应用程序的安装(几乎总是为真),并且没有其他应用程序使用相同版本的共享库(通常情况下是非常流行的项目除外),那么你就会占用更多的共享库空间。在共享库文件中有额外的信息,因为你有两个文件,而不是一个,所以你增加了磁盘分配开销 – Jay 2009-09-11 21:22:20

0

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

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

1

好吧,我现在已经知道共享库的使用有其速度的缺点。我发现这篇关于dynamic linking and loading的文章。加载过程似乎比我预期的要长得多。

0

对我而言很明显的一个选择是将多个程序静态链接到一个二进制文件中。通过这种方式,您可以继续共享尽可能多的代码(可能比以前更多),但是您也可以避免动态链接程序的开销,并节省系统上动态链接程序的空间。

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

2

这可以帮助其他有类似的问题:

启动为什么花了这么长时间在我的情况是,海湾合作委员会的默认设置是所有符号导出库的内部原因。 一个很大的改进是设置一个编译器设置“-fvisibility = hidden”。

的LIB拥有自营出口的所有符号都与声明

__attribute__ ((visibility("default")))

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

相关问题