共享对象/ DLL是否由不同的进程加载到不同的内存区域?

时间:2013-06-28 23:14:58

标签: 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的其他进程将冗余地加载到内存中,否则不应该允许系统忽略引用计数。 / p>

2。)如果这是真的,那么在同一个进程中多次加载DLL时,引用计数DLL的重点是什么?将同一个DLL加载到同一个进程中会有什么意义?我能想到的唯一可行理由是,如果一个EXE引用了两个DLL,并且其中一个DLL引用了另一个,那么对于同一个库,至少会有两个LoadLibrar()和两个FreeLibrary()调用。

我知道我好像在回答自己的问题,但我只是假装。我想肯定地知道。

1 个答案:

答案 0 :(得分:3)

共享库或DLL将为代码部分加载一次,对于任何可写数据部分加载多次[可能通过" copy-on-write",所以如果你有大块内存主要是读取,但是一些小部分被写入,只要它们没有从原始值改变,所有DLL都可以使用相同的部分]。

但是,可能会多次加载DLL。加载DLL时,会加载一个基地址,这是代码启动的地方。如果我们有一些进程,比如使用两个DLL,由于它们之前的加载,使用相同的基地址[因为使用它的其他进程并不使用两者],那么必须再次在不同的基地址加载DLL。对于大多数DLL而言,这是相当不寻常的。但它可能发生。

每个负载的引用计数点是它允许系统知道何时卸载模块是安全的(当referencecount为零时)。如果我们有两个不同的系统部分,都希望使用相同的DLL,并且它们都加载了这个DLL,那么当系统的第一部分关闭DLL时,你真的不想让系统崩溃。但是当系统的第二部分关闭DLL时,我们也不希望DLL留在内存中,因为这会浪费内存。 [想象一下,这个应用程序是一个在服务器上运行的进程,每周都会从服务器下载新的DLL,所以每周都会发布最新的"加载DLL(具有不同的名称)。几个月之后,你的整个记忆都充满了这些应用程序"陈旧,未使用过的" DLL' S]。当然还有一些场景,例如你所描述的,DLL在哪里使用LoadLibrary调用加载另一个DLL,并且主可执行文件加载了相同的DLL。同样,您需要两次FreeLibrary次调用才能关闭它。