【发布时间】:2016-06-08 22:12:54
【问题描述】:
我正在尝试创建一个多次重新加载共享库的应用程序。但是在某个时间点,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 创建的未使用命名空间?
【问题讨论】:
-
可能的答案可以在这里找到:stackoverflow.com/questions/14892101/…。我怀疑您的 lib.so 正在分配 TLS 数据,并且由于您将每个线程加载 10 次,因此可能会耗尽线程的存储空间。
-
TLS = Thread Local Storage,& ThreadLocal 对象中可能有太多内容。 A link 描述分配 TLS。
test_thread不需要将 thread_id 作为参数传递。 thread_id 不是int类型,并且每个id都可以通过thread.get_id访问。启动线程的更短方法:for(int i=0; i<10;i++) threads.push_back(thread(test_thread));并加入它们...for(auto& thread: threads) thread.join(); -
@qexyn lib.so 在这个例子中是从空文件编译的,所以只有
dlmopen分配 TLS 数据。我以前见过这个问题,但是自从 lib.so 使用-fPIC编译后,它已经使用了-ftls-model=global-dynamic。此外,看起来dlclose实际上并没有释放内存,接下来dlmopen创建了导致泄漏的新对象。 -
你能不能通过使用
dlopen并添加属性RTLD_NOW | RTLD_GROUP | RTLD_LOCAL来获得相同的结果。 -
你不能有很多命名空间——它在我系统的手册页中提到了
The glibc implementation supports a maximum of 16 namespaces,并且没有清理链接映射命名空间的工具。您最好通过仅卸载和重新加载库来为库回收相同的命名空间,而不是尝试继续创建新的命名空间(但这都是猜测)。您可以使用dlinfo来获取链接映射ID,以继续将其用于同一库的后续dlmopen 调用;您只需要在重新打开之前继续关闭。
标签: c++ linux shared-libraries