Ele*_*ito 12 c c++ linux gcc dlopen
我的程序dlopen
用来加载共享对象,然后dlclose
卸载它.有时这个共享对象会再次加载.我注意到静态变量没有重新初始化(这对我的程序来说至关重要)所以我在之后添加了一个测试(dlopen
with RTLD_NOLOAD
)dlclose
来查看库是否真的被卸载了.果然,它还在记忆中.
然后我尝试dlclose
反复调用,直到库真的被卸载,但我得到的是一个无限循环.这是我用来检查库是否已卸载的代码:
dlclose(handles[name]);
do {
void *handle = dlopen(filenames[name], RTLD_NOW | RTLD_NOLOAD);
if (!handle)
break;
dlclose(handle);
} while (true);
Run Code Online (Sandbox Code Playgroud)
我的问题是,dlclose
考虑到我的dlopen
调用是唯一加载它的地方,我的共享对象之后没有被卸载的可能原因是什么.你能否提出一个行动方案来追查问题的根源?另外,为什么重复调用dlclose
没有效果,它们每个都递减引用计数,不是吗?
编辑:刚刚发现只有当我用gcc编译时才会发生这种情况.有了clang,一切都很好.
Mec*_*cki 16
POSIX标准实际上不需要dlclose
从地址空间卸载库:
虽然从地址空间中删除结构不需要 dlclose()操作,但禁止实现这样做.
资料来源:公开集团基本规格问题6
这意味着除了使句柄无效之外,dlclose
根本不需要做任何事情.
有时卸载也会被系统延迟,它只是将库标记为"要删除",并且实际上会在稍后的某个时间执行该操作(为了提高效率,或者因为现在根本无法执行该操作).但是,如果dlopen
在执行之前再次调用,则清除该标志并重新使用仍然加载的库.
在某些情况下,系统肯定知道库中的某些符号仍在使用中,在这种情况下,它不会从地址空间中卸载它以避免悬空指针.在某些情况下,系统并不确定它们是否正在使用中,但它也可能无法确定它们不是,更好的安全而不是遗憾,在这种情况下它永远不会真正从内存中删除该库.
还有其他更加模糊的情况取决于操作系统类型,通常也在版本上.例如,一个常见的Linux问题是如果您创建了一个使用STB_GNU_UNIQUE符号的库,该库被标记为"不可卸载",因此将永远不会被卸载.见这里,这里(DF_1_NODELETE
指未卸),并在这里.因此,它还可以取决于编译器生成的符号或符号类型.尝试readelf -Ws
在您的库上运行并查找标记为的对象UNIQUE
.
一般来说,你不能真正依赖于dlclose
你所期望的工作.在实践中,我看到它在过去十年中"失败"而不是"成功"(好吧,它从未真正失败过,它通常不会从内存中卸载库;但它按照标准的要求工作).
这不是您所有问题的答案,但这是可以帮助您避免dlclose
. 这个问题提出了一个关于如何影响重新加载共享库行为的线索:您可以使用编译器标志-fno-gnu-unique
。
来自gcc
/ 的手册页g++
:
-fno-gnu-unique
在具有最新 GNU 汇编器和 C 库的系统上,C++ 编译器使用“STB_GNU_UNIQUE”绑定来确保内联函数中的模板静态数据成员和静态局部变量的定义即使在存在“RTLD_LOCAL”的情况下也是唯一的;这是必要的,以避免两个不同的“RTLD_LOCAL”插件使用的库出现问题,这取决于其中一个插件中的定义,因此在符号绑定方面与另一个不同意。但这会导致受影响的 DSO 忽略“dlclose”;如果您的程序依赖于通过“dlclose”和“dlopen”重新初始化 DSO,您可以使用 -fno-gnu-unique。
是否-fno-gnu-unique
默认使用取决于 GCC 的配置方式:--disable-gnu-unique-object
默认启用此标志,--enable-gnu-unique-object
禁用它。
动态库加载有很多怪癖。依赖操作系统来初始化静态变量充满了问题。您最好要么完全避免它,要么使用插件加载器来为您处理所有特殊情况。
我建议您查看glib 模块。 Glib提供了一种独立于平台的加载动态库的方式。您可以使用这些回调:
他们可以处理分配和取消分配任何资源。您可以动态分配您需要的内容,而不是依靠操作系统以可靠的方式为您分配静态数据。
您需要做的就是在动态库中定义这些函数,然后使用以下命令加载和卸载它们:
归档时间: |
|
查看次数: |
6400 次 |
最近记录: |