静态库和动态库

513 阅读6分钟
1、什么是静态库和动态库?

静态和动态是相对编译期和运行期而言的,静态库和动态库都是程序编译好的二进制文件。

  • 静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库;
  • 动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入。 静态库:是一堆.o文件的集合。当程序在启动的时候,会将 App 的代码(包括静态库的代码)一起在加载到 App 所处的内存地址上。

动态库:一个已经链接完全的镜像,又叫image。可以在运行或者启动的时候加载到内存中,加载到一块独立的于 App 的内存地址中;

2、存在形式

静态库:以 .a 或者 .framework 为文件后缀名;.a 是一个纯二进制文件,.framework 中除了有二进制文件之外还有资源文件。.a 要有 .h 文件以及资源文件配合,.framework 文件可以直接使用。总的来说,.a + .h + sourceFile = .framework

动态库:以 .dylib 或者 .framework 为文件后缀名

3、使用区别
  • 静态库链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝; 利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中。它的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去。当然这也会成为它的缺点,因为如果静态函数库改变了,那么程序必须重新编译。

IMG_2087.PNG

  • 动态库链接时不复制,程序运行时由系统动态加载到内存,供程序调用,而且系统只加载一次,多个程序共用,节省内存。相对于静态函数库,动态函数库在编译的时候,并没有被编译进目标代码中,程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响程序,所以动态函数库的升级比较方便。

IMG_2089.PNG

4、静态库的处理方式

对于一个静态库而言,其实已经是编译好的类似一个 .o 的集合,这里并没有连接。在 build 的过程中只会参与链接的过程,而这个链接的过程简单的讲就是合并,并且链接器只会将静态库中被使用的部分合并到可执行文件中去。相比较于动态库,静态库的处理起来要简单的多,具体如下图:

iShot_2022-05-24_22.29.26.png

  • 链接器会将所有 .o 用到的 global symbol 和 unresolved symbol 放入一个临时表,而且是 global symbol 是不能重复的。
  • 对于静态库的 .o,链接器会将没有任何 symbol 在 unresolved symbol table 的给忽略。
  • unresolved symbol 类似 extern int test(); .h 的声明。
  • global symbol 类似 void test() { print(“test”) } .m 的实现。
  • 最后,链接器会用函数的实际地址来代替函数引用。
5、动态库的处理方式
  • 首先,对于动态库而言其实分动态链接库和动态加载库两种的,这两个最本质的区别还是加载时间。

    动态链接库:在没有被加载到内存的前提下,当可执行文件被加载,动态库也随着被加载到内存中。在 Linked Framework and Libraries 设置的一些 share libraries(随着程序启动而启动)。

    动态加载库:当需要的时候再使用 dlopen 等通过代码或者命令的方式来加载(在程序启动之后)。

  • 但是不论是哪种动态库,相比较与静态库,动态库处理起来要棘手的多。由于动态库是动态的,所以事先不知道某个函数的具体地址,因此动态链接器在链接函数的时候需要做大量的工作。

  • 而实现这个动态链接是使用了 Procedure Linkage Table (PLT)。首先这个 PLT 列出了程序中每一个函数的调用,当程序开始运行,如果动态库被加载到内存中,PLT 会去寻找动态的地址并记录下来,如果每个函数都被调用过的话,下一次调用就可以通过 PLT 直接跳转了,但是和静态库还是有点区别的是,每一个函数的调用还是需要通过一张 PLT。这也正是所有静态链接做的事情都搬到运行时来做,会导致更慢的原因。

6、动态库的作用
  • 应用插件化

    • 每一个功能点都是一个动态库,在用户想使用某个功能的时候让其从网络下载,然后手动加载动态库,实现功能的的插件化
    • 虽然技术上来说这种动态更新是可行的,但是对于 App Store 上上架的 App 是不可以的。iOS8 之后虽然可以上传含有动态库的 App,但是苹果不仅需要你动态库和 App 的签名一致,而且苹果会在上架的时候再经过一次 App Store 的签名。所以想在线更新动态库,首先得有苹果 App Store 私钥,而这个基本不可能。
    • 除非应用不需要通过 App Store 上架,比如企业内部的应用,通过企业证书发布,那么就可以实现应用插件化在线更新动态库。
  • 共享可执行文件

    • 在其它大部分平台上,动态库都可以用于不同应用间共享,这就大大节省了内存。从目前来看,iOS 仍然不允许进程间共享动态库,即 iOS 上的动态库只能是私有的,因为我们仍然不能将动态库文件放置在除了自身沙盒以外的其它任何地方。
    • iOS8 上开放了 App Extension 功能,可以为一个应用创建插件,这样主 App 和插件之间共享动态库还是可行的。
7、优缺点

静态库:

优点

  • 执行速度快
  • 可执行程序不依赖库的存在

缺点

  • 文件体积相对较大
  • 更新困难,维护成本高

动态库:

优点

  • 可执行文件体积小,节省空间
  • 易于链接,便于更新维护

缺点

  • 文件执行速度相对较慢
  • 可执行程序依赖库文件的存在