卸载动态库需要两次dlclose()调用吗?

10

我有一个动态库,使用dlopen()加载,然后使用dlclose()卸载;

如果我没有包含任何Objective-C代码,则dlopen()需要一个dlclose()调用,这是预期的行为。但是,当我将任何Objective-C代码添加到目标中时,我遇到了问题,需要进行两个dlclose()调用才能卸载已加载的库。

这是一种预期行为吗?我该如何解决它?


你确定你的库没有以隐藏的方式被“dlopen”两次吗?或者可能存在一个错误,例如内存泄漏,正在覆盖“dlopen”句柄附近的内存吗? - Basile Starynkevitch
dlopen会对库句柄进行引用计数。如果dlopen被执行了两次,那么需要执行两次dlclose()才能卸载该库。如果包含obj-C代码,则可能需要动态库。在这种情况下,当您运行程序时,第一个dlopen可能已经被执行。 - Finslicer
是的,我确定它没有被重复dlopen。您可以尝试使用带有Objective-C代码的动态库,在主程序中使用dlopen后跟随dlclose的简单程序。 - RLT
@Finslicer:我确定程序开始时不需要动态库。正如我所说,即使是一个简单的主函数使用dlopen和dlclose也不能按预期工作,如果有Objective-C代码的话。 - RLT
1个回答

32

虽然我意识到您正在使用的是 dlopen,而不是 CFBundle 或者 NSBundle。然而,《加载代码编程主题》手册中写道:

在Cocoa应用程序中,不应该使用 CFBundle 函数来加载和卸载可执行代码,因为 CFBundle 不支持 Objective-C 运行时。 NSBundle 可以正确地将 Objective-C 符号加载到运行时系统中,但由于运行时限制,没有方法可以卸载 Cocoa 组件包。

以及:

由于 Objective-C 运行时系统的限制,NSBundle 无法卸载可执行代码。

这使我怀疑当您加载库时,它会向 Objective-C 运行时注册自己,然后运行时会再次调用 dlopen(或以某种方式增加库的引用计数)。

我搜索了 Objective-C 运行时源代码,并找到了这个

// dylibs are not allowed to unload
// ...except those with image_info and nothing else (5359412)
if (result->mhdr->filetype == MH_DYLIB  &&  _hasObjcContents(result)) {
    dlopen(result->os.dl_info.dli_fname, RTLD_NOLOAD);
}

是的,Objective-C运行时会调用dlopen来加载你的库,并阻止它被卸载。如果你欺骗性地调用dlclose两次,那么会出现问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接