【问题标题】:CLR memory consumption problemCLR内存消耗问题
【发布时间】:2010-11-10 13:41:23
【问题描述】:

CLR 的一个问题是它在缺少 RAM 的情况下是非常糟糕的行为(当托管进程的一些内存被分页时,这会导致整个系统完全冻结,即使 Ctrl-Alt-Del 屏幕也可以'无法访问。我认为原因是 GC 尝试构建可达对象图并尝试扫描进程的所有内存,从而导致大量的页入/页出操作。
这给我的 .NET 程序带来了问题,因为当输入数据很大时它会消耗大量 RAM。

我更愿意向用户显示“内存不足”消息,而不是完全挂起他的系统 ^_^
有什么方法可以实现吗?

【问题讨论】:

  • 问题的根本原因可能是您的计算机的物理内存太少,无法有效执行所需的工作负载。最好的解决方案可能是增加物理内存或减少工作量。
  • 同意。并且可能是一个严重碎片化的页面文件。
  • @Martin,我的电脑没问题。问题是输入数据可以是任意大小,因此任意数量的 RAM 都可能太小。
  • @Hans,猜错了。 GC/分页问题可以杀死任何 PC。
  • @fithu:那么也许您需要重写您的应用程序以不将所有输入数据读入 RAM。或者,如果您想阻止用户读取过多数据,请在读取数据之前给出错误消息,而不是尝试想出一个技巧来通知用户已读取过多数据。

标签: .net performance clr


【解决方案1】:

使用 MemoryFailPoint,您可以告诉 .NET 您将需要一定数量的内存。但问题是即使这个系统也包含交换空间。

我相信在这里要达到你想要达到的目标是非常困难的。比如说,你会使用一些系统指标和性能指标来找出有多少物理内存可用,并在此基础上执行一些任务。如果在您完成此检查后,一个不同的进程进入了一个抓取物理内存,那么您的原始计算将不再适用,并且您的一些内存将被推送到交换。

我有一个建议。您可以有一个配置设置,其中包含应用程序使用的最大允许内存量?有了这个,你可以:

  1. 尝试根据例如计算出您的应用程序消耗了多少资源。网络连接(如果您的应用程序是网络服务器)并根据最大内存消耗限制连接数,或者

  2. 您可以运行第二个线程,每 10 秒或每分钟检查一次 GC.GetTotalMemory() 的总内存消耗,并开始拒绝连接(再次,如果您的应用程序是网络服务器)最大。

这应该是一个配置设置,而不是例如可用的物理内存量,因为您不知道机器上正在运行哪些其他应用程序。

【讨论】:

  • 这太糟糕了。我可以想象会发生这种情况。我有一个建议。是否可以选择具有应用程序使用的最大允许内存量的配置设置?我不知道这有多可行,但也许您可以限制应用程序对资源的消耗以大致保持在这些限制内。您甚至可以使用辅助线程每隔 10 秒或每 10 秒或每分钟检查一次 GC.GetTotalMemory() 的总消耗量,并在超过限制后开始拒绝连接(如果您是网络服务器)。
【解决方案2】:

有一些系统调用来获取进程的大小和机器上的 RAM 帐户可能会有所帮助。

过去有很多关于编写可以处理分页的 GC 的研究,但我希望它们永远不会发布,因为这些天 RAM 越来越大。 (基本理想是不收集任何被分页的对象,并尝试在操作系统分页之前收集页面上的所有对象。但是您需要知道分页可能指向的所有对象出对象。)

您可以使用结构数组,然后传递索引,以减少您拥有的对象数量,从而减少 GC 必须遵循的指针数量。仅当您在 RAM 中有大量相同类型的数据时才值得这样做。

【讨论】:

  • 好吧,当操作系统试图调出一些托管内存时,他们至少可以让 CLR 显示错误消息而不是冻结整个系统。
  • @fithu,没有那么简单,任何 GC 都可以根据对象的聚集程度来处理某种程度的分页。例如,相互指向的对象大多同时创建。
  • 是的,RAM 变大了……是的,任务并不简单……但是,无论如何……我想,在任何情况下,任何程序都不能冻结整个系统。这显然是一个错误。
【解决方案3】:

在 Windows 中,您可以使用 Job Object 对进程可以分配的虚拟内存量施加硬性限制。 CLR 将在达到此限制时自动进行垃圾收集,如果无法释放足够的空间,则抛出 OutOfMemoryException。您还可以限制进程的工作集而不是虚拟内存。这允许进程根据需要进行分配,但它会被换出而不是消耗 RAM,并且系统不会挂起。我已经成功地使用 Job Objects 来达到这个目的(在运行大型作业时保持机器响应)。

要从 .NET 创建作业对象,您必须使用对 Win32 API 的 PInvoke 调用。这个article on CodeProject 解释了这个过程。

【讨论】:

    【解决方案4】:

    让 IIS 托管进程并使用 IIS 中的内存控件来限制使用的内存量。希望这会更频繁地强制 GC 并最大限度地减少对长时间运行的 GC 会话的需求。我想这种行为是由于您的应用如何从代际方面使用内存,例如在大量小对象中,这些对象 1) 长期存在,2) 在内存中移动。

    其他类似 .NET/CLR 内存控制问题和解决方案的链接

    Configure .NET CLR RAM usage
    Restricting .Net CLR memory usage
    Virtual and Physical Memory / OutOfMemoryException
    Preventing OutOfMemoryException with GC.AddMemoryPressure()?
    Force garbage collection of arrays, C#
    examples of garbage collection bottlenecks
    Suppressing C# garbage collection
    how to profile .net garbage collector?

    如果您使用的是大对象堆 (LOH)

    .NET Collections and the Large Object Heap (LOH)
    Large Object Heap Fragmentation

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 2012-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多