【问题标题】:Prevent .NET Garbage collection for short period of time在短时间内阻止 .NET 垃圾收集
【发布时间】:2011-08-25 17:45:19
【问题描述】:

我有一个处理大量数据的高性能应用程序。它在很短的时间内接收、分析和丢弃大量信息。这会导致我目前正在尝试优化的大量对象流失,但它也会导致次要问题。当垃圾收集启动时,它会在清理东西时导致一些长时间的延迟(我的意思是 10 到 100 毫秒)。 99% 的时间这是可以接受的,但是对于大约 1-2 分钟的短暂时间窗口,我需要绝对确定垃圾收集不会导致延迟。我知道这些时间段何时会发生,我只需要一种方法来确保在此期间不会发生垃圾收集。该应用程序是使用 .NET 4.0 Framework 用 C# 编写的,如果重要的话,它会使用托管代码和非托管代码。

我的问题是;

  1. 是否可以暂时暂停整个程序的垃圾收集?
  2. 是否可以在我需要释放垃圾收集的窗口之前使用 System.GC.Collect() 强制进行垃圾收集,如果这样做,我将在多长时间内释放垃圾收集?
  3. 人们对最大限度地减少对垃圾收集的总体需求有什么建议?

注意 - 这个系统相当复杂,包含许多不同的组件。我希望避免采用必须在程序的每个类上实现自定义 IDisposable 接口的方法。

【问题讨论】:

  • 每个类的自定义IDisposable 实现如何帮助解决您的问题?这些对象在处理后仍然需要进行 GC,不是吗?
  • IDisposable 与垃圾回收无关。
  • @LukeH - 通过 IDisposable 接口的大量工作,我可以让每个对象检查应用程序是否处于关键时期,并在该时期完成之前阻止最终确定。这种方法需要付出很多努力,并且有很多可能的缺点,但理论上可以使用。一旦关键时期结束,就会从大量突然完成的物体中进行大量清理。不是特别漂亮。
  • @LukeH 使用 IDisposable 接口,您可以在对象完成之前捕获它。此时,您检查程序中的单例引用以确定应用程序是否处于关键路径状态。如果是这样,您将完成短路并将对象添加到清理队列以供以后处理。只要该对象在该清理队列中被引用,它就不会受到 GC 的影响。当关键路径状态完成时,清理队列中的所有对象都被销毁并最终确定。老实说,我根本不喜欢这个,我不确定不会有很大的副作用。这只是一个想法。

标签: c# performance garbage-collection


【解决方案1】:

.NET 4.6 增加了两个新方法:GC.TryStartNoGCRegionGC.EndNoGCRegion 就是为了这个。

【讨论】:

  • 感谢您提供新信息。如果我在这个问题相关的时候把它拿回来,那就太好了。希望它能帮助遇到同样问题的新人。
【解决方案2】:
GCLatencyMode oldMode = GCSettings.LatencyMode;

// Make sure we can always go to the catch block, 
// so we can set the latency mode back to `oldMode`
RuntimeHelpers.PrepareConstrainedRegions();

try
{
    GCSettings.LatencyMode = GCLatencyMode.LowLatency;

    // Generation 2 garbage collection is now
    // deferred, except in extremely low-memory situations
}
finally
{
    // ALWAYS set the latency mode back
    GCSettings.LatencyMode = oldMode;
}

这将允许您尽可能多地禁用 GC。它不会做任何大型对象集合,直到:

  • 您拨打GC.Collect()
  • 您将GCSettings.LatencyMode 设置为LowLatency 以外的其他值
  • 操作系统向 CLR 发送低内存信号

执行此操作时请小心,因为当您位于 try 块中时,内存使用量会急剧上升。如果 GC 正在收集,那么它这样做是有原因的,只有在系统上有大量内存时才应该认真考虑这一点。

关于问题三,如果您通过文件系统 I/O 或网络接收信息,也许您可​​以尝试重用字节数组等对象?如果您将该信息解析为自定义类,请尝试重用这些信息,但如果不了解您具体在做什么,我无法给出太多好的建议。

这里有一些 MSDN 文章也可以提供帮助:

注意: GCSettings.LatencyMode = GCLatencyMode.LowLatency 只能在GCSettings.IsServerGC == false 时设置。 IsServerGC可以改成App.config:

  <runtime>
    <gcServer enabled="false" />
  </runtime>

【讨论】:

  • 如果您不介意,可以问几个问题。 1. 我知道发生关键事件的一般时间段,但它是由从多播广播中接收到的数据元素触发的。我想防止 GC 延迟接收该数据。你推荐什么? 2. 进入 ConstrainedRegion 或切换到 LowLatency 模式是否会影响性能?是否可以在我看到特定数据项而不影响输入性能时立即完成?顺便说一句,非常有用的东西 - 谢谢。
  • 对于 1,我会说如果一般时间段很短,大约几秒钟,那么您可以将 GC 设置为 LowLatency 直到消息到达。再长一点,我想说,据我所知,你无能为力。如果您绝对不能有 GC 延迟,您可以尝试在另一个进程中接收广播,然后将其编组到您的主进程,但这会使事情变得非常复杂。对于 2,我相信进入 CER 会在您进入和退出它时对性能造成影响,但我从未测量过它,也没有自己设置延迟模式。
猜你喜欢
  • 2015-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
  • 1970-01-01
  • 2011-03-05
  • 2015-10-08
相关资源
最近更新 更多