【问题标题】:Maximum Memory a .NET process can allocate.NET 进程可以分配的最大内存
【发布时间】:2010-10-30 09:03:29
【问题描述】:

垃圾收集器可以为 .NET 进程分配的最大内存是多少?当我编译到 x64 时,Process.GetCurrentProcess.MaxWorkingSet 返回大约 1.4GB,但是当我编译到 AnyCPU (x64) 时返回相同的数字。对于 x64,它应该更像任务管理器中显示的“限制”值。我怎样才能得到正确的数字,在所有情况下都超过时会导致 OutOfMemory-Exceptions?

该方法应返回的一些示例:

1) 机器配置:x64-Windows,4GB 物理内存,4GB 页面文件
- 作为 64 位进程:8GB
- 作为 32 位进程:1.4GB

2) 机器配置:x64-Windows,1GB 物理内存,2GB 页面文件
- 作为 64 位进程:3GB
- 作为 32 位进程:1.4GB

3) 机器配置:x32-Windows,4GB 物理内存,4GB 页面文件
- 作为 64 位进程:不会发生
- 作为 32 位进程:1.4GB

4) 机器配置:x32-Windows,512MB 物理内存,512MB 页面文件
- 作为 64 位进程:不会发生
- 作为 32 位进程:1.0GB

【问题讨论】:

标签: .net memory-management


【解决方案1】:

这不取决于你有多少内存吗?

理论上,我认为 x64 进程可以分配 EB(千兆字节?)的 RAM,即很多。但是如果你这样做了,你的机器应该会开始疯狂地分页并且通常会死机。

在 32 位模式下有所不同,因为您不能在 Windows 的任何进程中分配超过 1GB 的 RAM(是的,有一些方法可以绕过它,但它并不漂亮)。实际上,这意味着每个 .NET 进程大约需要 7-800meg,因为 .NET 保留了一些空间。

无论哪种方式,在 32 位中,您最多可以使用 3GB - 操作系统为自己保留 1GB 的虚拟空间。

在 64 位中,它应该是 2^64,这是一个很大的数字,但http://en.wikipedia.org/wiki/X86-64 说它是 256TB 的虚拟空间和 1TB 的 REAL RAM。无论哪种方式,它都比您机器中可能拥有的要多得多,因此它会命中页面文件。

使用 64 位操作系统和 64 位运行时, 基于 .NET 2.0 的应用程序现在可以 将 500 倍以上的内存用于数据 例如基于服务器的缓存。

这也有一些很好的信息http://www.theserverside.net/tt/articles/showarticle.tss?id=NET2BMNov64Bit

顺便说一句,如果您在 x64 机器上(即 x64 机器 + x64 操作系统),为 AnyCPU 和 x64 编译会做同样的事情 - 它在 x64 模式下运行。唯一的区别是如果你使用 AnyCPU vrs x86:

  • x64 OS/.NET,AnyCpu:x64 应用程序
  • x64 OS/.NET, x64: x64 应用程序
  • x64 OS/.NET, x32: x32 应用程序(x64 .NET 框架同时安装了 x32 和 x64 版本的 Fx)

  • x32 OS/NET,AnyCPU:x32 应用

  • x32 OS/.NET、x64:崩溃并烧毁宝贝! (实际上,它只是优雅地死去)
  • x32 OS/.NET,x32:x32 应用程序。

【讨论】:

  • 但是我如何才能获得机器的实际内存限制?
  • 我将您的答案标记为不好,因为您混合了所有内容。 3 gigs 内存是可以容纳 1 个或多个进程的最大可用物理内存。任何进程都可以访问完整的 4 gigs 空间(32 位寻址),无法在物理内存中的内存将被缓存(如果缓存设置正确)。 3 gigs 也不完全正确。您必须设置 XP,默认情况下,应用程序的最大内存只有 2 gigs,操作系统(物理内存)只有 2 gigs。
  • 抱歉,Eric,但您需要仔细阅读并实际尝试一下。 32 位系统的理论限制可能是 4GB,但 windows 将您限制为 3GB(另一个 GB 用于系统,您必须在引导参数中使用 /3GB 才能得到它),而每个进程都有一个4GB 空间、windows 或 .NET FX 对不执行特殊操作(SQL 和 Exchange 执行)的进程强制执行 1GB 限制。
  • 简单的测试方法:循环分配内存,看看何时出现内存不足错误。对我来说,在 32 位系统上它总是在 750-800MB 左右。
【解决方案2】:

Windows 可以配置为按需分配更多的页面文件空间,或者on request
Job objects 可以防止消耗超过一定数量的内存。
堆的碎片和它的代际性质(加上需要将大的东西放在大对象堆中)

所有这些都意味着硬限制在现实中没有多大用处,意味着回答“理论上我可以分配多少内存”这个问题比你想象的要复杂得多。

因为它很复杂,任何人提出这个问题可能是试图做一些错误的事情,应该将他们的问题重定向到更有用的东西。

您要做什么才能使这样的问题显得有必要?

“我只想知道进程的当前内存负载何时会出现问题 所以我可以采取一些行动,比如释放自定义缓存中的某些项目。”

没错。这是一个更容易处理的问题。

按复杂度排列的两种解决方案:

  1. 让你的缓存使用WeakReferences
    • 这意味着系统将为您释放几乎神奇的东西,但您几乎无法控制诸如替换政策之类的事情
    • 这依赖于缓存数据远大于键和弱引用的开销
  2. 注册notification of Garbage Collections
    • 这让您可以控制释放事物。
    • 您依赖于系统具有适合 GC 生成的最大大小,这可能需要一段时间才能达到稳定状态。

注意事项。 与重新计算/重新请求数据相比,维护这个庞大的缓存(通过它的声音进入磁盘)真的成本更低吗?
如果您的缓存在通常/连续请求的项目之间表现出较差的局部性,那么将花费大量精力将数据分页进出。具有有效调整的 relpacement 策略的较小缓存很有可能表现得更好(并且对其他正在运行的程序的影响要小得多)

顺便说一句:在 .Net 中,由于用于内存管理的核心 CLR 结构的限制,任何可变大小的对象(字符串、数组)的大小都不能超过 2GB。 (上述任一解决方案都将受益于此)

【讨论】:

  • 我只想知道进程的当前内存负载何时会出现问题,以便我可以采取诸如释放自定义缓存的某些项目之类的操作。该值不需要 100% 准确,只是对我的缓存的提示。我目前有可用物理内存的数量作为限制,但对于 32 位进程,障碍较低。
  • 顺便说一句:动态页面文件大小的好处,我错过了,但现在,我会对当前的限制感到满意。
  • 嗯,这个问题是这个问题的某种后续问题:stackoverflow.com/questions/930198/…。我在兜圈子。
  • 好的,但你开始有所收获了。听起来你会从 GC 通知 API 中受益,如果没有第 2 代集合,那么你会很好
猜你喜欢
  • 2014-10-10
  • 2014-12-29
  • 1970-01-01
  • 2012-02-23
  • 2023-03-20
  • 2023-03-20
  • 2010-10-17
  • 2013-06-17
  • 1970-01-01
相关资源
最近更新 更多