1.为什么要有动态链接
静态链接使得不同的程序开发者和部门能够相对独立地开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发效率。但是慢慢地静态链接的诸多缺点也逐步暴露出来,使得人们不得不寻找一种更好的方式来组织程序的模块。
- 浪费内存
- 浪费磁盘空间
- 模块更新困难
- 程序的更新、部署、发布困难
2.动态链接的基本思想
如何解决空间浪费和更新困难这两个问题?
最简单的方法就是把程序的模块相互分割开来,形成独立的文件,而不再将它们静态链接在一起。简单来讲,就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。
也就是说把链接这个过程推迟到了装载的时候再进行,这就是动态链接的基本思想。
以 program0 和 program1 为例,假设我们保留 program0.o、program1.o、和 a.o 三个目标文件。
- 当我们要运行 program1 这个程序时,系统首先加载 program1.o,当系统发现 program1.o 用到了 a.o,即 program1.o 依赖于 a.o,那么,系统接着加载 a.o。如果 progrom1.o 或者 a.o 还依赖于其他目标文件,系统会按照上述方法,全部将它们加载至内存。
- 所有需要的目标文件加载完毕后,如果依赖关系满足,系统开始进行链接工作。链接过程的原理和静态链接相似,包括符合解析、地址重定位等
- 完成这些步骤后,系统开始把控制权交给 program1.o 的程序入口,程序开始运行-这时如果我们需要运行 program0,那么系统只需要加载 program0.o,而不需要重新加载 a.o(内存中已经存在 a.o 的副本),系统只需要将 program.o 和 a.o 链接起来
很明显,上述做法解决了共享目标文件多个副本浪费磁盘和内存空间问题,可以看到磁盘和内存只要一份 a.o 而不是两份。
动态链接是把链接这个过程从装载前延迟到了装载的时候。看到这里,可能有人会问,动态链接岂不是会造成程序的运行很慢?
答案是的,动态链接确实会导致程序启动变慢,不过随着 CPU 性能的提高,两者差异已不是很大了。据估算动态链接与静态链接相比性能损失大约在 5%以下。
当然经过实践证明,这点性能上的损失用来换取程序在空间上的节省和程序构建和升级时的灵活性,是相当值得的。
3.动态库的制作和使用
制作
首先将源码(*.c)编译成目标文件(*.o):
//-fPIC 生成地址无关码 gcc -c log.c -o log.o -fPIC
然后将目标文件打包成动态库:
gcc -shared -o liblog.so log.o
使用
动态库的使用和静态库相同,比如编译 main.c 为可执行程序,链接动态库 liblog.so
// -L 指定链接路径 gcc main.c -o main -L./ -llog
- 静态链接:直接运行。
- 动态链接:将共享库 liblog.so 复制到系统的特定路径;设置环境变量 LD_LIBRARY_PATH。
export LD_LIBRARY_PATH=/home/user/logpath:$LD_LIBRARY_PATH