垃圾收集器是否受益于对Collect和WaitForPendingFinalizers()的多次调用?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾收集器是否受益于对Collect和WaitForPendingFinalizers()的多次调用?相关的知识,希望对你有一定的参考价值。
我发现这个在线代码是在取消初始化Excel Interop对象后附加的:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
这是对DRY的准违反(以口吃的方式连续两次调用GC.Collect()和GC.WaitForPendingFinalizers())有什么用处,或者只是浪费时间?
这来自Microsoft documentation站点上的示例程序。
//Force garbage collection.
GC.Collect();
// Wait for all finalizers to complete before continuing.
// Without this call to GC.WaitForPendingFinalizers,
// the worker loop below might execute at the same time
// as the finalizers.
// With this call, the worker loop executes only after
// all finalizers have been called.
GC.WaitForPendingFinalizers();
当垃圾收集器找到可以回收的对象时,它会检查每个对象以确定对象的终结要求。如果一个对象实现了一个终结器并且没有通过调用SuppressFinalize来禁用终结,那么该对象将放在一个标记为准备完成的对象列表中。垃圾收集器为此列表中的对象调用Finalize方法,并从列表中删除条目。此方法将阻塞,直到所有终结器都运行完成。
运行终结器的线程未指定,因此无法保证此方法将终止。但是,当WaitForPendingFinalizers方法正在进行时,此线程可能被另一个线程中断。例如,您可以启动另一个等待一段时间的线程,然后在此线程仍处于挂起状态时中断此线程。
据我所知,没有明确的迹象表明两次调用它的好处。
垃圾收集器是否受益于多个调用...
你不是这样做有利于GC,远非如此,你这样做是为了强制Excel.exe终止。它不能停止,直到所有的interop包装器(RCWs)完成。单个GC.Collect()调用足以设置该列车运动。
随后的GC.WaitForPendingFinalizers()调用是可选的。没有什么理由想要等到它们完成。在一个表现良好的程序中,这最多只能在几毫秒内完成。如果拥有这些interop包装器的线程将要终止,那么这一点非常重要。这并不常见。如果您不确定那么使用它没有错。
第二次收集+等待呼叫没用。 RCW非常小,因此Collect调用不会释放任何有用的内存量。等等无法等待。
放置此代码往往很重要。如果它出现在使用Excel接口的相同方法中,则在附加调试器时它将不会执行任何操作。将它放在方法的调用者中是最好的。 this post解释了为什么调试器起作用。
简短的回答是,不,你不应该叫它两次。
现在,让我们深入挖掘一下。 GC使用基于生成的方法。也就是说 - 堆被分成块,用于优化GC,因此它实际上在较小的内存区域上运行。您可以了解有关GC如何工作here的更多信息。
当GC运行时,它会回收当前一代中的所有对象,这些对象没有强*引用(* - 可以使用System.WeakReference
类型来引用对象,同时允许GC回收它)。在垃圾收集中幸存下来的那些对象被移动到下一代。如果下一代足够,GC也会在它上面运行 - 进一步移动幸存的对象。话虽如此,你可以看到第二次运行GC的可能性几乎没有差别。
但是,在负载很重的情况下,对象的创建速度非常快,两次后续调用之间的时间间隔就足够了(取决于线程的状态,优先级 - 调用的时间)来创建足够的对象,可以添加一些记忆的重量。在那种情况下,后续调用可以产生影响并清理大量内存。虽然这种情况有可能发生,但实际情况并非如此。原因是,如果有这样的负载,它可能会继续,所以调用GC两次将没有太大的区别......
以上是关于垃圾收集器是否受益于对Collect和WaitForPendingFinalizers()的多次调用?的主要内容,如果未能解决你的问题,请参考以下文章