C ++强制卸载共享库

时间:2016-06-08 22:12:54

标签: c++ linux shared-libraries

我正在尝试创建一个多次重新加载共享库的应用程序。但是在某个时间点,dlmopen失败并出现错误

/usr/lib/libc.so.6: cannot allocate memory in static TLS block

以下是重现此问题的最小代码:

#include <dlfcn.h>
#include <cstdio>
#include <vector>

int main() {
  for (int i = 0; i < 100; ++i) {
    void *lib_so = dlmopen(LM_ID_NEWLM, "lib.so", RTLD_LAZY | RTLD_LOCAL);
    if (lib_so == NULL) {
      printf("Iteration %i loading failed: %s\n", i, dlerror());
      return 1;
    }
    dlclose(lib_so);
  }

  return 0;
}

并清空lib.cpp,用

编译
g++ -rdynamic -ldl -Wl,-R . -o test main.cpp
g++ -fPIC -shared lib.cpp -o lib.so

更新

即使只有一个帖子,它似乎崩溃了。问题是:如何强制库卸载或销毁使用LM_ID_NEWLM创建的未使用的命名空间?

2 个答案:

答案 0 :(得分:2)

流程可用的链接映射名称空间的数量存在内置限制。这在评论中的记录很少:

  

glibc实现最多支持16个命名空间

在手册页中。

创建链接映射名称空间后,不支持通过任何API“擦除”它。这就是它的设计方式,如果不编辑glibc源并添加一些钩子,就没有真正的解决办法。

使用命名空间重新加载库实际上并没有重新加载库 - 您只需加载库的新副本。这是命名空间的用例之一 - 如果您多次尝试dlopen同一个库,则会获得相同库的相同句柄;但是,如果在另一个命名空间中加载第二个实例,则不会获得相同的句柄。如果要完成重新加载,则需要使用dlclose卸载库,一旦释放了对库的最后一个剩余引用,它将卸载库。

如果您想尝试“强制卸载”某个库,那么您可以尝试发出多个dlclose调用,直到它卸载为止;但是如果你不知道库做了什么(例如衍生线程),那么在这种情况下可能无法防止崩溃。

答案 1 :(得分:0)

较旧的glibc版本可能存在一些与此相关的错误:

https://bugzilla.redhat.com/show_bug.cgi?id=89692  https://sourceware.org/bugzilla/show_bug.cgi?id=14898

您使用的是哪个版本?尝试使用更新的glibc版本,您的代码在我的计算机上运行得非常好(glibc 2.23)。