无论调用多少次,dlclose都不会真正卸载共享对象 [英] dlclose doesn't really unload shared object, no matter how many times it is called

查看:436
本文介绍了无论调用多少次,dlclose都不会真正卸载共享对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序使用 dlopen 来加载共享对象,然后使用 dlclose 来卸载它。有时候这个共享对象再次被加载。我注意到静态变量没有被重新初始化(对我的程序至关重要),所以我添加了一个测试( dlopen RTLD_NOLOAD dlclose 之后,查看库是否真的被卸载。果然,它仍然在内存中。

然后我试着重复调用 dlclose 直到库真的被卸载,但我得到的是一个无限循环。这是我用来检查库是否被卸载的代码:

  dlclose(handles [name]); 

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

dlclose(handle);
} while(true);

我的问题是,在$ <$ c $之后我的共享对象没有被卸载的可能原因是什么c> dlclose ,因为我的 dlopen 调用是它加载的唯一地方。你能提出一个行动路线来追踪问题的根源吗?此外,为什么重复调用 dlclose 没有任何作用,它们都是递减引用计数,不是吗?



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

解决方案

POSIX标准实际上不需要<$ c

lockquote

尽管dlclose()操作 >不需要从地址空间中移除结构
,也不允许从
这样做。


blockquote>

资料来源: Open Group Base Specifications Issue 6 < a>



这意味着除了使句柄无效之外, dlclose 不需要做任何事情。 p>

有时卸载也会被系统延迟,它只会标记库被删除,并会在稍后的时间执行该操作(为了提高效率或因为它会现在根本无法执行该操作)。但是,如果您在执行之前再次调用 dlopen ,该标志将被清除,并且仍然会加载该库。



在某些情况下,系统肯定知道库的某些符号仍在使用中,在这种情况下,它不会从地址空间卸载它以避免悬挂指针。在某些情况下,系统并不确定它们是否在使用中,但它也不可能确切地告诉他们它们不是,比对不起更安全,在这种情况下它永远不会真正从内存中移除该库。

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



一般来说,您不能真正依赖 dlclose 来按照您的预期工作。在实践中,我认为它在过去的十年中比成功更经常失败(当然,它从来没有真正失败过,它通常并没有从图书馆中卸载图书馆,但它按照标准的要求工作) p>

My program uses dlopen to load a shared object and later dlclose to unload it. Sometimes this shared object is loaded once again. I noticed static variables are not re-initialized (something which is crucial to my program) so I added a test (dlopen with RTLD_NOLOAD) after dlclose to see if the library is really unloaded. Sure enough, it was still in memory.

I then tried calling dlclose repeatedly until the library is really unloaded, but what I got was an infinite loop. This is the code I'm using to check if the library was unloaded:

dlclose(handles[name]);

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

  dlclose(handle);
} while (true);

My question is, what are the possible reasons for my shared object not being unloaded after dlclose, given that my dlopen calls are the only places where it is loaded. Can you suggest a course of action to track down the source of the problem? Also, why are repeated calls to dlclose have no effect, they are each decrementing the reference count, aren't they?

EDIT: Just found out that this happens only when I compile with gcc. With clang, everything is just fine.

解决方案

The POSIX standard actually does not require dlclose to ever unload a library from address space:

Although a dlclose() operation is not required to remove structures from an address space, neither is an implementation prohibited from doing so.

Source: The Open Group Base Specifications Issue 6

That means other than invalidating the handle, dlclose is not required to do anything at all.

Sometimes unloading is also delayed by the system, it just marks the library as "to be removed" and will actually perform that operation at some later time (for efficiency or because it would simply not be possible to perform that operation right now). However, if you call dlopen again before it ever was performed, the flag is cleared and the still loaded library is reused.

In some cases the system knows for sure that some symbols of the library are still in use, in that case it will not unload it from address space to avoid dangling pointers. In some cases the system doesn't know for sure that they are in use, but it also can impossibly tell for sure that they are not, better being safe than sorry, it will just never really remove that library from memory in such a case.

There are other more obscure cases depending on operation system kind and often also on version. E.g. a common Linux issue is if you created a library that uses STB_GNU_UNIQUE symbols, that library is marked as "not unloadable" and thus will simply never be unloaded. See here, here (DF_1_NODELETE means not unloadable) and here. So it can also depend on what symbols or kind of symbol a compiler generates. Try running readelf -Ws on your library and look for objects tagged as UNIQUE.

In general, you cannot really rely on dlclose to work as you might expect. In practice I saw it "fail" more often than "succeed" in the last ten years (well, it never really failed, it just often did not unload the library from memory; yet it worked as required by the standards).

这篇关于无论调用多少次,dlclose都不会真正卸载共享对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆