插件热更新后界面不更新问题
开发环境
操作系统 : Linuxqt版本 : qt5
背景
在开发qt插件的过程中发现的,原本是想做一个插件热插拔的功能,作用是在主程序不关闭的情况下,替换同名称的插件共享库并生效
但在自测的时候发现,替换了共享库之后发现新库的内容并没有生效
问题排查过程
我是使用QPluginLoader去实现qt插件,这样可以直接导出类,方便主程序加载调用
https://gitee.com/learninglzq/qt-use-problem/tree/master/hot-test-code
在发现替换共享库不生效后,我首先是设置环境变量QT_DEBUG_PLUGINS=1没有什么异常输出,接着我思考了一下,加载库不生效也是是qt接口用的不对,加载接口如下:
bool QPluginLoader::load() //加载QLibrary::LoadHints QPluginLoader::loadHints() const //设置加载标志
load接口在底层调用的是dlopen函数,loadHints设置的参数会影响调用dlopen时的传参
QLibrary::PreventUnloadHint参数对应的是dlopen的RTLD_NODELETE标志
所以我调用loadHints函数时,仅传参QLibrary::ResolveAllSymbolsHint避免其他参数影响
结果发现替换后还是没有效果,无奈只能去社区提问了,大佬们建议我试试设置LD_DEBUG环境变量,看看输出,果然是发现了有异常输出
89768: file=libQt5Sql.so.5 [0]; needed by /home/lzq/hot-plugin/testmain/libxxx.so [0]
89768: file=libQt5Sql.so.5 [0]; generating link map
89768: dynamic: 0x00007fb9b8b30cd0 base: 0x00007fb9b8af0000 size: 0x00000000000416c8
89768: entry: 0x00007fb9b8af0000 phdr: 0x00007fb9b8af0040 phnum: 9
89768:
89768: activating NODELETE for /home/lzq/hot-plugin/testmain/libxxx.so [0]
activating NODELETE这个字段很值得怀疑,因为和RTLD_NODELETE很像,看看是什么意思
activating NODELETE 表示动态链接器(ld.so)为某个共享库启用了NODELETE标志,强制该库在程序运行期间不被卸载,即使其引用计数归零。此机制用于确保关键库的稳定性,防止意外卸载导致程序崩溃或资源泄漏。
因为出问题的工程中业务代码太多,不知道是哪部分影响的,我自己又写了一个demo进行比较,发现替换库正确且没有出现activating NODELETE
接着我在网上查了一下可能会出现activating NODELETE标记的原因
(1) dlopen上显示的使用 RTLD_NODELETE(2) 其他模块使用了插件库中的符号,资源未释放(可能释放了也会被标记NODELETE)(3) 内联函数可能导致被标记
知道了可能会产生的原因,但不知道哪部分代码导致的,这就很难受,只能祭出二分法删代码来确定,发现QDBusInterface::call会导致NODELTE,最后还是在社区上了解到,QDBus模块中有使用内联函数
修改方法
网上、社区上、公司的人都问完了,没有明确的线索
我只能独自思考,在考虑到跨模块引用其他符号可能到导致NODELETE时,我突然想到linux下默认符号是不隐藏的,主程序是我实现的,就是调用了一个导出类的接口,没有别的,也许加载库时用某些底层的东西引用了吧
总之,我想到了使用g++编译参数隐藏不需要导出的符号,解决了这个问题