C++ 强制卸载共享库
Posted
技术标签:
【中文标题】C++ 强制卸载共享库【英文标题】:C++ force unloading shared library 【发布时间】: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
创建的未使用命名空间?
【问题讨论】:
可能的答案可以在这里找到:***.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 调用;您只需要在重新打开之前继续关闭。
【参考方案1】:
对进程可用的链接映射命名空间的数量存在内置限制。这在评论中记录得很差:
glibc 实现最多支持 16 个命名空间
在手册页中。
创建链接映射命名空间后,不支持通过任何 API 将其“擦除”。这只是它的设计方式,如果不编辑 glibc 源代码并添加一些钩子,就没有真正的解决方法。
使用命名空间重新加载库实际上并不是重新加载库 - 您只是加载库的新副本。这是命名空间的用例之一——如果您多次尝试dlopen
同一个库,您将获得同一个库的相同句柄;但是,如果您在不同的命名空间中加载第二个实例,您将不会获得相同的句柄。如果要完成重新加载,则需要使用dlclose
卸载库,这将在释放对库的最后剩余引用后卸载库。
如果您想尝试“强制卸载”一个库,那么您可以尝试发出多个 dlclose
调用,直到它卸载;但是,如果您不知道库做了什么(例如生成的线程),那么在这种情况下可能无法防止崩溃。
【讨论】:
【参考方案2】:旧的 glibc 版本可能有一些与此相关的错误:
https://bugzilla.redhat.com/show_bug.cgi?id=89692 https://sourceware.org/bugzilla/show_bug.cgi?id=14898
你用的是什么版本?尝试使用较新的 glibc 版本,您的代码在我的计算机上运行良好(glibc 2.23)。
【讨论】:
有趣。在 Arch Linux 上使用 glibc 2.24 崩溃。你用什么系统? 我使用的是 Ubuntu 16.04以上是关于C++ 强制卸载共享库的主要内容,如果未能解决你的问题,请参考以下文章