防止在短时间内收集.NET垃圾


70

我有一个高性能的应用程序,正在处理大量数据。它正在非常短的时间内接收,分析和丢弃大量信息。这会导致大量对象流失,而我目前正在尝试优化该对象流失,但同时也会导致第二个问题。当垃圾回收启动时,它可能会导致某些长时间的清理工作(很长一段时间,我的意思是10到100毫秒)。99%的时间是可以接受的,但是对于大约1-2分钟长的短暂时间,我需要绝对确保垃圾回收不会造成延迟。我知道这些时间段何时会提前发生,我只需要一种方法来确保在此期间不会发生垃圾收集。该应用程序是使用.NET 4以C#编写的。

我的问题是;

  1. 是否可以暂时暂停整个程序的垃圾回收?
  2. 是否可以使用System.GC.Collect()强制在我需要免费垃圾收集的窗口之前进行垃圾收集,如果我将多长时间免费使用垃圾收集?
  3. 人们对减少总体垃圾收集有何建议?

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



IDisposable每个类的自定义实现如何帮助您解决问题?这些对象在处置后仍需要进行GC处理,不是吗?
路加福音

4
IDisposable与垃圾回收无关。
戴夫·怀特

@LukeH-通过使用IDisposable接口进行大量工作,我可以让每个对象检查该应用程序是否处于关键时期,并防止在该时期结束之前进行最终确定。此方法将花费很多精力,并且可能会有很多缺点,但是从理论上讲可以使用。一旦关键时期结束,大量的突然敲定的物体将被清除掉。不是特别漂亮。
drobertson

3
@LukeH使用IDisposable接口,您可以在完成该对象之前捕获该对象。届时,您将检查程序中的单例引用,以确定应用程序是否处于关键路径状态。如果是这样,则可以缩短终结处理的时间,然后将对象添加到清理队列中以备后用。只要在该清理队列中引用了该对象,它就不受GC的约束。关键路径状态完成后,清除队列中的所有对象将被销毁并完成。老实说,我根本不喜欢这种方式,而且我不确定不会有巨大的副作用。只是一个想法。
drobertson

Answers:



78
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 == falseIsServerGC可以更改为App.config

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

如果您不介意,请问几个问题。我知道一般情况下会发生关键事件的时间段,但是它是由多播广播中接收到的数据元素触发的。我想防止GC延迟该数据的接收。你有什么建议?2.进入ConstrainedRegion或切换到LowLatency模式时,性能是否受到影响?我一看到特定的数据项就可以完成这项工作,而不会影响入门性能吗?顺便说一句,非常有用的东西-谢谢。
drobertson

1
对于1,我要说的是,如果一般时间段很小(大约几秒钟),则可以将GC设置为LowLatency直到消息到达。不止如此,我想说的是我无能为力。如果绝对没有GC延迟,则可以尝试在另一个进程中接收广播,然后将其封送给您的主进程,但这会使事情变得非常复杂。对于2,进入CER时,我相信它会在您进入和退出时带来性能下降,但是我从未测量过它,也没有自己设置延迟模式。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.