我正在尝试创建一个多次重新加载共享库的应用程序。但是在某个时候,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创建的未使用的命名空间?
发布于 2017-01-11 09:20:03
对于一个进程可用的链接映射命名空间的数量有一个内置限制。这一点在评论中记录得相当少:
glibc实现最多支持16个命名空间。
在手册页上。
一旦创建了链接映射命名空间,就不支持通过任何API“擦除”它。这正是它的设计方式,如果不编辑glibc源代码和添加一些钩子,就没有真正的解决方法。
使用名称空间来重新加载库实际上并不是重新加载库--您只是加载库的一个新副本。这是名称空间的用例之一--如果您多次尝试使用同一个库,您将得到同一个库的同一个句柄;但是,如果您将第二个实例加载到不同的名称空间中,则不会得到相同的句柄。如果要完成重新加载,则需要使用dlclose卸载库,一旦释放了对库的最后剩余引用,库将卸载。
如果您想要“强制卸载”一个库,那么您可以尝试发出多个dlclose调用,直到它卸载为止;但是,如果您不知道库做了什么(例如生成线程),那么在这种情况下可能无法防止崩溃。
发布于 2017-01-10 10:26:44
较早的glibc版本可能存在一些与此相关的bug:
bug.cgi?id=89692 bug.cgi?id=14898
你用的是什么版本?尝试使用更新的glibc版本,您的代码在我的计算机上运行得很好(glibc 2.23)。
https://stackoverflow.com/questions/37713826
复制相似问题