使用dlopen显式加载共享库后删除/替换库文件会产生什么影响?
dlopen常见问题解答
问题1:dlopen显式加载共享库后,删除或替换该共享库文件会产生什么影响?
Linux环境下dlopen加载共享库采用mmap映射机制,加载完成后内核会持有该文件的引用计数:
- 直接删除原库文件:仅删除文件系统层的inode引用,文件实际存储的数据不会立刻释放,直到所有引用该库的进程执行
dlclose关闭库、或者进程退出后,存储空间才会被回收。已完成加载的当前进程运行不受任何影响,库函数调用可以正常执行。 - 替换原库文件:分两种场景
- 直接覆盖写入原库文件:会修改磁盘上被映射的文件内容,进程访问到被修改的内存页时会触发未定义行为,大概率出现崩溃、逻辑异常问题
- 先删除原库文件,再写入新库为同名路径:旧进程仍使用原有加载的库内容不受影响,仅新启动进程、或新执行dlopen该路径的逻辑会加载新库
问题2:dlopen是否会将整个共享库全部加载到内存中?运行过程中是否仍需要访问原库文件?如何强制全量加载?
默认情况下dlopen不会将整个so文件全量加载到物理内存,采用的是请求分页加载机制:仅完成进程虚拟地址空间的映射,只有当程序实际访问到对应代码/数据页时,内核才会触发缺页中断将对应页从磁盘读取到物理内存。因此运行过程中如果访问到未加载的页,仍需要访问文件系统中的原库文件。
如果要强制将整个so文件全量加载到内存,不再依赖原库文件,可以用以下两种方案:
- 调用
dlopen成功后,遍历该so映射的整个虚拟地址范围,手动读取每个内存页的第一个字节,触发缺页中断将所有页加载到物理内存 - 调用
mlock()系统调用,将so映射的整个地址范围锁在物理内存中,该操作不仅会强制加载所有页,还能避免页被操作系统换出到swap分区
问题3:标记位RTLD_NOW的作用是否是将整个库全部加载到内存中?
不是。RTLD_NOW的作用是要求dlopen在返回前完成共享库所有未定义符号的解析和重定位,与之对应的RTLD_LAZY标记则是等到符号第一次被调用时才执行解析。
RTLD_NOW仅影响符号解析的时机,和共享库的代码、数据页是否全量加载到物理内存没有任何关联,哪怕使用了RTLD_NOW标记,未被访问到的内存页仍然不会被主动加载到物理内存。
内容的提问来源于stack exchange,提问作者prgbenz
相关产品推荐
相关产品推荐

