Bra*_*don 8 c++ dll shared-libraries
我试图弄清楚操作系统如何处理加载相同 DLL/共享库的多个不相关进程。我关心的操作系统是 Linux 和 Windows,但在较小程度上也是 Mac。我认为我的问题的答案对于所有操作系统都是相同的。
我对显式链接特别感兴趣,但我也想知道隐式链接。我认为两者的答案也将相同。
这是迄今为止我发现的关于 Windows 的最佳解释:
“系统在所有加载的模块上维护每个进程的引用计数。调用 LoadLibrary 增加引用计数。调用 FreeLibrary 或 FreeLibraryAndExitThread 函数减少引用计数。当引用计数达到零或进程终止时,系统卸载模块(无论引用计数如何)。” - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx
但它留下了一些问题。
1.) 不相关的进程是否冗余地加载同一个 DLL(即 DLL 在内存中存在多次)而不是使用引用计数?(IE,进入每个进程自己的“地址空间”,因为我想我理解它)
如果在进程终止后立即卸载 DLL,这让我相信使用完全相同 DLL 的其他进程将冗余加载到内存中,否则不应允许系统忽略引用计数。
2.) 如果这是真的,那么当您在同一进程中多次加载它们时,引用计数 DLL 的意义何在?将同一个 DLL 两次加载到同一个进程中有什么意义?我能想到的唯一可行的原因是,如果一个 EXE 引用了两个 DLL,而其中一个 DLL 引用了另一个,那么对于同一个库,至少会有两个 LoadLibrar() 和两个 FreeLibrary() 调用。
我知道这似乎是我在这里回答我自己的问题,但我只是假设。我很想知道。
共享库或 DLL 将为代码部分加载一次,并为任何可写数据部分加载多次 [可能通过“写时复制”,因此,如果您有大块内存,主要是读取,但有些很小部分被写入,所有的 DLL 都可以使用相同的部分,只要它们没有改变原始值]。
但是,DLL 可能会被多次加载。当一个 DLL 被加载时,它被加载一个基地址,这是代码开始的地方。如果我们有一些进程,它正在使用,例如,两个 DLL,由于它们之前的加载,使用相同的基地址 [因为使用它的其他进程不会同时使用两者],那么其中一个 DLL 将不得不在不同的基地址再次加载。对于大多数 DLL 来说,这是相当不寻常的。但它可能发生。
每次加载引用计数的要点是它允许系统知道何时卸载模块是安全的(当引用计数为零时)。如果系统有两个不同的部分,都想使用相同的 DLL,并且它们都加载该 DLL,那么当系统的第一部分关闭 DLL 时,您真的不想导致系统崩溃。但是当系统的第二部分关闭 DLL 时,我们也不希望 DLL 留在内存中,因为那样会浪费内存。[假设这个应用程序是一个在服务器上运行的进程,每周都会从服务器下载新的 DLL,因此每周都会加载“最新”的 DLL(具有不同的名称)。几个月后,您的整个内存将充满此应用程序“旧的、未使用的”DLL]。LoadLibrary调用,并且主可执行文件加载完全相同的 DLL。同样,您确实需要两次FreeLibrary调用才能关闭它。