动态库相比静态库的区别是:静态库是编译时就加载到可执行文件中的,而动态库是在程序运行时完成加载的,所以使用动态库的程序的体积要比使用静态库程序的体积小,并且使用动态库的程序在运行时必须依赖所使用的动态库文件,而使用静态库的程序一旦完成编译,就不再需要依赖的静态库文件。
在Linux平台下,动态库的调用分为显式和隐式两种方式。
隐式调用§
又叫隐式加载或载入时加载。
通过在编译时设置包含动态库的头文件(-Idir... -include file
),并指明动态库的位置和名称(-Ldir... -lnamespec(libnamespec.so)
)。
隐式调用由系统完成加载,对编程者透明。隐式调用必须包含动态库中的头文件。
显式调用§
在运行时加载,在程序运行过程中通过dlopen
指定动态链接库文件,然后通过dlsym
获取动态库里函数的地址。
相比隐式调用,显式调用需要在程序中实现,写明要加载的动态库以及调用函数的名称。
使用dlopen链接并不是在进程启动时候加载映射的,而是当进程运行到使用dlopen的地方才加载。因此如果一个程序进行显式调用,但并没有附带显式调用加载的动态库文件,该程序仍能正常启动。而且当运行逻辑没有触发调用dlopen的代码时,即使缺少动态库文件程序仍然可以正常运行。
显式调用时,由编程者实现进行加载并负责卸载。这样好比对动态申请内存空间,需要使用时申请,不使用时即可释放。因此显式调用内存使用更为合理,大型项目应使用显式调用。
常用工具§
readelf§
--dyn-syms
显示文件动态符号表中的入口。
-d
显示文件动态段内容。
ldd§
使用dlopen加载的动态库通过ldd无法查看到。
ldd -u
查看不需要链接的动态库文件。
多链接的动态库文件正是由于在编译时的设置导致,因为动态链接有加载文件的过程
-Wl,--as-needed
链接选项,仅当符号在目标文件和必要的库中无法找到时,才会从这些动态库中加载。
strace§
用于查看系统调用和信号。
通过strace可以看到程序加载了哪些动态库文件,可以看到程序通过dlopen加载的动态库文件。