动态库热加载指的是在程序运行时,动态地加载动态库,从而达到不停止程序的情况下,更新程序的功能。
C++ 程序在运行时有两种方式加载动态连接库:隐式链接和显式链接。
- 隐式链接就是在编译的时候使用 -l 参数链接的动态库,进程在开始执行时就将动态库文件映射到内存空间中。
- 显式链接使用 libdl.so 库的 API 接口在运行中加载和卸载动态库,主要的 API 有 dlopen、dlclose、dlsym、dlerror。
使用动态链接可以解决静态链接带来的可执行文件过大的问题(每次都要将静态库编译进可执行二进制文件)、解决版本不兼容问题、减少内存的使用(仅在必要时加载动态库,有点懒加载的味道)。
dlopen()
函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()
的调用进程用以获取函数地址或者全局变量地址。使用 dlclose()
来卸载打开的库。
void* dlopen(const char * pathname, int mode);
void* dlsym(void* handle,const char* symbol);
int dlclose(void *handle);
简单的例子
#include <stdio.h>
void hello(void)
{
printf("hello\n");
}
编译命令gcc -shared -o hello.so hello.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv)
{
void *handle;
void (*callfun)();
char *error;
handle = dlopen("/root/tmp/hello.so",RTLD_LAZY); //如果hello.so不是在LD_LIBRARY_PATH所申明
//的路径中必须使用全路径名
if(!handle)
{
printf("%s \n",dlerror());
exit(1);
}
dlerror();
callfun=dlsym(handle,"hello");
if((error=dlerror())!=NULL)
{
printf("%s \n",error);
exit(1);
}
callfun();
dlclose(handle);
return 0;
}
编译命令gcc -o hello_dlopen hello_dlopen.c -ldl
(需要连接 dl 库)