【问题标题】:Call GC.Collect Before Throwing OutOfMemoryException在抛出 OutOfMemoryException 之前调用 GC.Collect
【发布时间】:2011-06-08 23:16:23
【问题描述】:

有什么方法可以在抛出 OutOfMemoryException 之前调用 GC.Collect()?

我想我正在寻找一种方法来执行以下代码流:

Try to Allocate Memory
On Pass Return
Call GC.Collect()
Try to Allocate Memory
On Fail Throw New OutOfMemoryException()

我正在编写一个缓存实现,目前我遇到了内存异常,所以目前我正在使用它来解决它:

If GC.GetTotalMemory(False) >= cache.CacheMemoryLimit + (100 * 1024 * 1024) Then
    // When Total Memory exceeds CacheMemoryLimit + 100MB
    GC.Collect()
End If

【问题讨论】:

  • 如果您在创建新对象时内存不足,我认为运行时已经运行了垃圾回收。
  • @Simon 是的,通常抛出 OutOfMemoryException 是因为垃圾收集器无法为您的实例回收更多内存,这意味着静态引用或其他类型的内存泄漏。由于静态引用,类加载器特别容易泄漏。

标签: .net garbage-collection out-of-memory


【解决方案1】:

也许我不理解你的问题,但你不可能只捕获 OutOfMemoryException 的抛出并在那里调用 GC.Collect 吗?将 try/catch 放入一个循环中,该循环一直持续到您完成任务并确保它能够自行清理。

bool isFinished = false;
while (isFinished) {
  try {
    // do operations in here
  } catch (OutOfMemoryException oom) {
    GC.Collect();
  }

  // if you're done...
  isFinished = true;
}

请原谅使用 C# 伪而不是 VB,除非我别无选择,否则我尽量不要在 VB 中工作。

【讨论】:

  • 谢谢,这有助于找到我的问题,内存中的对象在应用程序尝试分配更多内存之前尚未完成最终确定。
  • 小心,我的测试似乎表明,在某些情况下,当您真的内存不足时,.NET 框架会引发其他异常(例如,在分配数组时我见过ArgumentException),并且有时您会遇到(无法捕获的)Win32 错误,这些错误会立即杀死您的程序。
【解决方案2】:

实际上,.NET 会很高兴地抛出内存不足异常,而它本来可以进行垃圾收集并成功。这是我对 Microsoft 的 .net 实施的少数抱怨之一。在一个或多个线程中分配并立即丢弃大量内存的单元测试似乎通过了。然而,我认为一旦老一代的大块超出范围,问题就开始了。那些东西不是马上捡起来的。

因此,例如,如果您的代码一次从磁盘读取一百万个 XmlDocument,那么您很可能会收到 OutOfMemory 异常,除非您每隔几个文档 GC.Collect()。

编辑:http://social.msdn.microsoft.com/forums/en-US/clr/thread/52a7eb17-ac05-470c-b063-a78427cd4406/

【讨论】:

    【解决方案3】:

    Out of Memory 异常的全部意义在于让您知道您的内存不足,毕竟系统的所有 GC 努力都失败了。如果您真的在使用缓存系统,那么您应该考虑查看弱引用或软引用。这些允许系统在内存紧张时丢弃项目,即使它们有对它们的引用。

    在缓存系统中,当你查找一个对象时,前一秒你会得到结果,下一秒你会得到一个 NULL,因为内存已经紧张到足以迫使系统丢弃弱引用的对象。此时,您的缓存重新创建对象,并将其放回缓存中,然后您继续前进,就好像这是您第一次引用该对象一样。

    【讨论】:

      【解决方案4】:

      调用 GC.Collect 可以修复与计时相关的 OutOfMemory 异常。 正如上面提到的杂耍清单 “.NET 会很高兴地抛出内存不足的异常,而它本来可以进行垃圾收集并成功。” 我有一个高速软实时视频处理系统,在重负载下偶尔会抛出 OutOfMemory 异常。将 GC.Collect 调用策略性地放置在已知的处理死区中(在下一个相机触发之前)解决了这些问题。授予另一种选择是根据需要手动处理对象,但是为什么我们要使用托管环境。我的应用程序是 x86 内存模型编译的事实可能会加剧这个问题。因此,如果您正在做一些内存异常密集的事情,并且觉得您在代码中拥有一个您认为适合进行垃圾收集的位置,那么就去做吧。 这已在此处广泛讨论:What's so wrong about using GC.Collect()?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-02-28
        • 2014-09-20
        • 1970-01-01
        • 1970-01-01
        • 2013-03-08
        • 2016-04-01
        • 1970-01-01
        相关资源
        最近更新 更多