【问题标题】:.NET assemblies memory usage.NET 程序集内存使用情况
【发布时间】:2013-05-20 15:46:36
【问题描述】:

假设我有两个完全独立的 .NET 应用程序,Foo.exeBoo.exe,它们都使用位于 Foo 和 Boo 的 bin 文件夹中的同一个库 TestLib.dll(两个副本)。

.NET 会加载这两个 dll,浪费size_of_dll * 2 大小的 RAM,还是会检查强程序集名称、大小等...并仅加载和加载两个程序集之一?

【问题讨论】:

  • 简而言之 - 是的。看看这个链接msdn.microsoft.com/en-us/library/windows/desktop/…
  • 我不知道,如果 windows 不这样做(例如,对于它自己的签名程序集),但这样做会疯狂。即使您具有相同的名称、版本和大小,您仍然可以在来自不同来源、提供者或区域(或修补程序集)的两个程序集之间存在位差异。
  • 程序集的大小与程序在运行时可以分配的内存量(最高 8Tb)相比是微不足道的。
  • No.. 我们的程序有总大小 > 400 Mb 的程序集,其中大部分现在用于不同的应用程序.. 所以用户会浪费大量的 RAM! 4aps * 300 Mb
  • 举例说明我们如何浪费内存

标签: c# .net dll .net-assembly


【解决方案1】:

你说得对,DLL 的一个特性是多个进程都使用该 DLL 可以共享某些部分以减少内存使用(这是 Windows 特性,并非特定于 .Net),但我相当肯定要使其工作,两个进程必须在磁盘上加载相同的物理 DLL,在这种情况下,您描述的场景不会发生这种情况。

如果您改为安装到公共位置(例如 GAC),则 Windows 将能够在多个进程之间共享 DLL 的某些部分以节省内存。对于 .net 程序集,您还需要 NGen the assembly in order to take advantage of this

请注意,“保存”的内存量不是size_of_dll,因为该 DLL 映像的某些部分无法共享,即该 DLL 的任何部分都可能被修改。这些部分仍然在多个进程中重复,以确保应用程序不会意外修改彼此的数据。

【讨论】:

  • If you instead installed into a common location (e.g. the GAC) then Windows would be able to share certain portions of the DLL across multiple processes in order to save memory. 真的吗?除了在 GAC 中,我认为他们可能也必须是 pre-jit (ngen) 吗?
  • @YK1 是啊,好像是这样
  • 我认为只有 Ngen 就足够了 - 但如果组装在 GAC 中,那么它的性能会更高。 GAC 不是强制性的。无论如何,我赞成你的答案,因为它比我的更完整。干杯!
【解决方案2】:

是的,DLL 将在每个 AppDomain 中加载一次。但是,您可以跨多个 AppDomain 共享 DLL 以减少内存使用。如code project article 中所述。

如果一个程序集在一个进程中被多个域使用,则 程序集的代码(但不是它的数据)可以由所有域共享 引用程序集。这减少了使用的内存量 运行时间。

【讨论】:

  • 我不认为AppDomains 可以共享。您可以跨AppDomain 边界编组变量,但我还没有遇到在进程之间“共享”AppDomains 的方法。
  • 否,但您可以跨多个应用程序域共享 DLL。
  • 不确定您所说的“共享 DLL”是什么意思。无论如何,问题在于两个独立的进程是否会使用相同的程序集。不是关于AppDomains
【解决方案3】:

如果您希望多个进程共享同一个程序集,您有两种选择:

  1. 您可以将程序集放在GACGlobal Assembly Cache 中。您可以使用GacUtil 来做到这一点。
  2. 您可以使用配置文件和codeBase 元素在一小部分应用程序之间共享私有部署的程序集。

【讨论】:

  • 谢谢。我知道......而且不仅放入 GAC,而且我可以使用 AssemblyResolve 事件在不同的进程中使用相同的程序集......但我开始怀疑。也许 .NET 会检查所有程序集,并通过从 GAC 外部的不同位置共享相同的程序集来减少内存使用和加载时间 ..
  • 查看我的最新编辑,您甚至可以共享私有部署的程序集!
【解决方案4】:

使用两个 .net 4.0 项目、一个类库和 Process Explorer 对此进行了测试 - 默认情况下,Visual Studio 将引用的 dll 复制到项目的 bin 目录。

Process Explorer 为引用的 dll 返回两个不同的地址,而为其他特定于 windows 的库返回相同的地址。

结论:是的,对于同一库在不同文件夹中的两个副本,由两个应用程序加载,同一个库可能会被加载两次。

【讨论】:

    【解决方案5】:

    我认为您是在询问程序集的代码是每个进程加载一次还是在本机 dll 等进程之间共享。答案是否定的,主要是因为代码不是原生的,它必须是 JIT。每个进程都会发生 Jitting。 Pre-jitted 程序集 (ngen) 能够共享代码。

    【讨论】:

      猜你喜欢
      • 2015-12-02
      • 2018-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多