【问题标题】:.NET JIT'ed assemblies in sharable pages可共享页面中的 .NET JIT 程序集
【发布时间】:2010-10-17 16:51:42
【问题描述】:

在终端服务环境中运行 .NET 2.0 WinForms 应用程序时,我看到了一些我无法解释的意外结果。我读过的所有内容都表明 JIT 程序集(即不使用 NGen 创建本机映像)导致所有代码空间都存储在私有页面中,从而增加了工作集大小/内存压力。然而,实际结果(使用 Process Explorer、VMMap 和 WinDbg 验证)表明,即使是 JIT 程序集也确实被放置在可共享页面中(并且当有多个应用程序实例运行时,即使在单独的 TS 下也确实是共享的会话/用户)。

谁能解释为什么会这样?这是在 W2K8 服务器环境中运行的,因此 ASLR 解释了为什么每个程序集缺少特定的基地址以及由此产生的变基不会导致问题。尽管如此,这些不是本机 PE 映像的事实似乎应该导致这些程序集的代码存储在私有页面中。

当我们开始调查使用 NGen 来减少内存压力时发现了这一点,但实际上发现它增加了工作集的大小 - 因为 JIT 的程序集已经被共享。

我找到的最新参考资料在这里,这与我们的实际发现再次不同:

http://blogs.msdn.com/morgan/archive/2009/03/07/developing-net-applications-for-deployment-on-terminal-services-or-citrix.aspx

编辑:我应该补充一点,自从第一次发布问题以来,Windows Server 2003 测试盒上的更多实验显然也表明 JIT 程序集在进程之间是可共享的。我仍然很难理解为什么我能找到的所有建议都表明 NGen 是必需的,但所有现实世界的证据都与此相矛盾。我真的希望这里的专家能提供一些启示。

谢谢!

编辑:我已经把我所有的 .NET / CLR 书籍都掸掉了,但对于搜索查询的想法已经用尽,试图解决这个问题;谁会通过帮助消除“我不明白发生了什么”的那种可怕的唠叨感觉来度过我的一天!?! :)

【问题讨论】:

  • 除非有任何确凿的证据表明 NGen 确实有助于内存使用(以及在我们的环境中启动时间的影响可以忽略不计),否则我们决定不继续生成程序集的本机图像。不过,我仍然想知道为什么我们会看到这种意外行为!

标签: .net memory windows-server-2008 jit ngen


【解决方案1】:

我认为您正在直接查看模块页面。当您 JIT 代码时,它不会显示在您的 DLL 下 - 它显示在运行时分配的内存中。您正在查看的模块页面主要是元数据和 IL,这就是它们仍然可以共享的原因。

作为一个实验,我写了一个小程序,生成30K个静态方法并调用它们。在我的系统上,这个程序的 JIT 版本有 8.2 MB 的专用内存,而 NGEN 版本有 3.8。

不过,即使在您的模块页面中,NGEN 也有助于内存使用。当运行时能够加载 NGEN 图像时,它不必读取模块的元数据来 JIT 代码。我的测试应用程序的 JIT 版本使用了 2.3MB 的工作集。 NGEN 版本使用 32 KB。

NGEN 还应该有助于缩短启动时间。对热启动时间的影响可以忽略不计,但对冷启动时间的影响(节省从磁盘读取所有这些页面的时间)可能很明显。

【讨论】:

  • 感谢您的回复!我将把事情分解并做一些更简单的测试,但我没有看到相同的结果。从我读过的内容(以及我引用的博客文章)来看,我真的应该看到模块页面的区别。 AFAIK,CLR 仍然需要读取元数据以支持反射、CAS 策略检查等; NGEN 并没有消除这一点。由于这是一个由许多用户运行的基于 TS 服务器的应用程序,因此内存使用很关键,而冷启动时间基本上是无关紧要的。
  • 没问题!反射等的元数据访问都是惰性的——没有任何东西急切地加载来支持这些场景。我知道在 TS 场景中,内存使用是关键因素。我鼓励你阅读这篇文章:msdn.microsoft.com/en-us/magazine/cc163610.aspx,如果你还没有。当您重新查看模块页面时,请查看 vmmap 中的 WS 列,而不是 size/commited。 WS 是实际使用中的页面大小,也就是我看到的 2.3MB 到 32KB。祝你好运!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-09
  • 2010-11-28
  • 2014-08-29
相关资源
最近更新 更多