我的程序使用dlopen加载共享对象,然后使用dlclose卸载共享对象。有时会再次加载此共享库。我注意到静态变量没有重新初始化(这对我的程序很重要),因此我在dlopen之后添加了一个测试(RTLD_NOLOADdlclose),以查看库是否确实已卸载。果然,它仍然在内存中。

然后,我尝试反复调用dlclose,直到真正卸载了该库为止,但是得到的是一个无限循环。这是我用来检查库是否已卸载的代码:

dlclose(handles[name]);

do {
  void *handle = dlopen(filenames[name], RTLD_NOW | RTLD_NOLOAD);
  if (!handle)
    break;

  dlclose(handle);
} while (true);

我的问题是,鉴于我的dlclose调用是唯一加载它的地方,因此在dlopen之后不卸载我的共享库的可能原因是什么?您能否建议采取行动来跟踪问题的根源?另外,为什么重复调用dlclose无效,它们每次都减少引用计数,不是吗?

编辑:刚发现,只有当我使用 gcc 进行编译时,才会发生这种情况。使用 clang ,一切都很好。

最佳答案

POSIX标准实际上不需要dlclose从地址空间中卸载库:



资料来源:The Open Group Base Specifications Issue 6

这意味着除了使句柄无效之外,dlclose根本不需要执行任何操作。

有时系统也会延迟卸载,它只是将库标记为“将要删除”,并且实际上会在以后的某个时间执行该操作(出于效率考虑,或者因为现在暂时无法执行该操作)。但是,如果在执行之前再次调用dlopen,则该标志将被清除,并且仍在加载的库将被重用。

在某些情况下,系统会确定该库的某些符号仍在使用中,在这种情况下,它将不会从地址空间中卸载该符号以避免悬空的指针。在某些情况下,系统无法确定它们是否正在使用中,但也无法确定是否存在它们,比后悔更安全,它永远不会真正从内存中删除该库。 。

还有其他更难理解的情况,具体取决于操作系统的种类,通常还取决于版本。例如。 Linux的一个常见问题是,如果您创建了一个使用STB_GNU_UNIQUE符号的库,该库将被标记为“不可卸载”,因此将永远不会被卸载。请参见herehere(DF_1_NODELETE表示不可卸载)和here。因此,它也可以取决于编译器生成的符号或符号类型。尝试在您的库上运行readelf -Ws并查找标记为UNIQUE的对象。

通常,您不能真正依靠dlclose来工作,就像您期望的那样。实际上,在过去的十年中,我看到它“失败”的频率要比“成功”的频率高(嗯,它从未真正失败过,它只是没有从内存中卸载该库;但是它按照标准的要求工作了)。

关于c++ - dlclose实际上不会卸载共享对象,无论它被调用了多少次,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24467404/

10-13 05:20