在进程之间共享dll - 虚拟内存似乎没有受益

时间:2011-06-24 20:35:20

标签: c# .net memory dll memory-management

我的意图是我的应用程序之间的共享dll,例如,如果我有2个加载20MB dll的应用程序,而不是使用200MB内存而另一个使用200MB内存的进程,其中一个将受益于共享和仅使用180MB内存。 我的问题在于记忆的定义,请继续阅读。

我创建了2个.net c#应用程序,它们引用并运行位于GAC中的大型dll(20MB)代码。 使用.NET Memory Profiler,我可以看到第二个进程使用的实际物理内存确实明显低于首先启动的物理内存(尽管它们是相同的)并且dll位于第一个进程的共享内存下处理。 然而,当用perfmon检查内存计数器时,我发现两个应用程序的虚拟内存增加(与dll的大小相关)增加了相同的大小,当单独运行每个应用程序时,它们会增加。

这导致了一个问题:如果只有物理内存从中受益,那么共享(内存经济智能)dll会有什么意义,而虚拟内存(从应用程序的角度来看,重要的是它)。

修改:感谢您的回答。根据答案,我想强调一点,我理解在内存中共享dll以节省物理内存的好处。我应该问的更精确的问题是: 从.net中的应用程序之间共享dll的方式是否有任何好处,应用程序明智(不是系统方面的)? 我问这个的原因是因为我关心我的应用程序正在使用的虚拟内存量(总计)。

5 个答案:

答案 0 :(得分:7)

RAM很重要。虚拟内存不需要任何费用,它是虚拟的。共享相同RAM的多个进程是一个大问题。任何Windows进程都依赖于kernel32.dll。但是在RAM中只有一个的代码副本。

利用托管程序中的进程共享代码需要运行ngen.exe,以便它们都能获得完全相同的机器代码。如果代码是即时编译的,则无法共享任何内容。

答案 1 :(得分:4)

  

如果只有物理内存从中获益,那么共享(内存 - 经济智能)dll会有什么意义,但从应用程序的角度来看,虚拟内存是重要的。

我不确定你是如何得出这个结论的。系统具有有限数量的物理内存,而不是虚拟内存,因此从长远来看,节省物理内存是非常重要的。

答案 2 :(得分:1)

您似乎没有正确地考虑这一点。应用程序的进程空间是它的虚拟内存。为了运行代码,必须将其映射到应用程序进程空间。否则,它将如何执行它实际上看不到的代码?

物理内存是共享的,但CPU必须能够看到虚拟内存才能执行它。

这样想。假设您和您的邻居共用一个游泳池。无论出于何种意图和目的,您都认为游泳池包含在您的房产中。只存在一个物理池,但每个人都将其视为“虚拟内存”的一部分。

答案 3 :(得分:1)

@duskwuff - 系统确实也有一定数量的虚拟内存,虽然理论上限制非常大(但实际上受页面文件大小的限制)。除此之外,之前答案所做的观察在某种程度上是正确的。

在Windows中,DLL具有"首选加载地址"内置于他们的形象。如果这与同一进程中任何其他DLL的加载地址冲突,那么加载器必须" rebase" DLL,基本上意味着通过并修复DLL中的绝对引用。此时,加载的内容不再与来自磁盘的内容相同(并且至关重要)与加载到任何其他进程地址空间的内容不同 - 这意味着它无法加载在进程之间共享。

此外,由于它与磁盘上的内容不同,如果需要换出,则需要将其写入页面文件(这是虚拟内存的位置)不存在于物理记忆中的。)

所以,虽然我不认为这是导致你在perfmon中看到的问题的原因,但在构建你的DLL时要记住这一点。如果DLL在加载时被重新定位,您将在VS控制台中看到调试输出。

您可以在构建时设置首选加载地址,或使用名为rebase post-build的SDK工具。因此,如果您要构建多个DLL,请确保其首选加载地址不会发生冲突。即使您只构建一个DLL,也应检查它是否与您的应用所依赖的其他任何内容发生冲突。

答案 4 :(得分:-1)

我的理解是通过GAC共享旨在节省硬盘空间,而不是内存空间。 ghimireniraj说,每个从GAC调用DLL的应用程序都将获得自己的DLL内存副本。