静态链接的特点
代码嵌入性:
在静态链接过程中,链接器会把程序所依赖的所有库函数的代码以及相关的数据,从对应的静态库(如在 C、C++ 语言中常见的.a 文件为静态库文件格式)中提取出来,与目标程序的代码整合在一起,最终生成一个可执行文件。这意味着最终的可执行文件包含了运行所需的全部代码,是一个完整独立的实体,不依赖外部的库文件在运行时进行额外的代码加载。例如,一个简单的 C 语言程序调用了printf
函数,如果采用静态链接,printf
函数对应的实现代码就会直接被拷贝到最终的可执行文件中。可移植性好:
由于可执行文件已经包含了所有需要的代码,将其拷贝到其他相同操作系统环境(比如同样是 Linux 系统或者同样是 Windows 系统)的机器上时,只要该机器的硬件能够支持,它通常就可以直接运行,不需要担心目标机器上是否安装了特定版本的库文件等问题,方便在不同配置但同类型的系统之间进行迁移使用。执行效率相对稳定:
因为所有代码在编译时就已整合到可执行文件中,程序运行时不需要在磁盘等存储介质中查找和加载外部的动态链接库,减少了运行时因查找库文件、动态链接等操作带来的时间开销,其执行效率相对比较稳定,可预测性强。不过,如果静态链接的库比较大,可能会导致可执行文件体积庞大,占用较多磁盘空间和内存加载时间,在一定程度上可能影响初始启动速度等情况。更新维护复杂:
如果程序依赖的静态库中的代码有更新或者修复了某些漏洞,比如某个被广泛使用的数学计算库有了性能优化的新版本,由于静态链接是将代码嵌入到可执行文件中,那么要让程序使用新的库代码,就需要重新编译整个程序,把新的库代码重新整合进去,不像动态链接那样可以方便地通过替换外部动态链接库来更新功能。占用磁盘空间大:
多个使用相同静态库的程序,每个程序都会把静态库中的相关代码复制一份到自己的可执行文件中,而不是共享同一份代码,所以会造成磁盘空间的浪费,特别是对于一些大型的、被众多应用依赖的基础库来说,这种重复占用磁盘空间的情况会比较明显。
动态链接的特点
共享库代码:
动态链接采用共享库(在 Linux 下常见的格式如.so 文件,在 Windows 下常见的是.dll 文件)的形式,多个应用程序可以共享同一个动态链接库中的代码和数据。例如,多个不同的图形界面程序都使用了系统提供的显示绘制相关的动态库,在内存中只需加载一份该动态库的代码,多个程序就可以在运行时调用其中的函数,这样可以有效节省磁盘空间以及内存空间,避免了静态链接那种每个程序都复制一份库代码的冗余情况。易于更新维护:
当动态链接库有更新时,比如修复了安全漏洞或者添加了新功能,只要更新磁盘上的动态链接库文件本身,使用该动态链接库的所有应用程序下次运行时就能自动使用更新后的版本,无需重新编译这些应用程序。例如,操作系统中很多核心的系统库通过动态链接的方式被众多程序依赖,当系统更新这些库来增强安全性时,各个应用程序可以无缝受益。减小可执行文件体积:
可执行文件中只需要记录所依赖的动态链接库的名称、版本等基本信息以及对库中函数调用的相关重定位信息等,不需要包含库函数的实际代码,所以可执行文件本身的体积相对静态链接生成的可执行文件会小很多,便于在磁盘上存储、传输等,尤其对于一些大型软件项目,这有助于降低整体的分发成本。运行时依赖强:
程序运行时需要依赖相应的动态链接库存在于系统中指定的搜索路径下(不同操作系统有不同的默认搜索路径设置,比如 Linux 系统下会查找/lib
、/usr/lib
等目录),如果动态链接库缺失、版本不匹配或者损坏,程序将无法正常启动或者在运行过程中出现错误,比如提示找不到某个.dll
文件等错误信息,这就对系统环境的配置和动态链接库的管理有一定要求。首次启动可能较慢:
因为程序在首次运行时,需要操作系统的动态链接器去查找、加载相应的动态链接库,并进行符号解析、重定位等操作,将程序中的函数调用和动态库中的实际函数地址关联起来,这个过程会有一定的时间开销,所以相比静态链接的程序,动态链接程序首次启动时可能会稍慢一些,但后续再次运行如果动态库已经加载到内存中,速度就会变快。