同步运行 GC.Collect
GC.Collect 似乎在后台线程中启动垃圾收集,然后立即返回。 如何同步运行GC.Collect
——即等待垃圾收集完成?
这是在 NUnit 测试的背景下。 我尝试将 gcConcurrent 设置添加到我的测试程序集的 app.config 文件中,我对 nunit.exe.config 进行了相同的尝试。 两者都没有任何效果——当我调试时,我仍然可以看到终结器正在“GC Finalizer Thread”上运行,而不是在调用 GC.Collect 的线程(NUnit 的“TestRunnerThread”)上运行,并且两个线程同时运行。
背景:如果我的测试泄漏(不调用 Dispose)特定的类,我希望我的测试失败。 因此,我向该类添加了一个终结器,用于设置静态 wasLeaked
标志; 然后我的测试 TearDown 调用 GC.Collect() ,然后如果 wasLeaked
为 true 则抛出异常。 但它并不是确定性失败,因为当它读取 wasLeaked
时,终结器通常还没有被调用。 (在垃圾收集最终完成之后,它反而失败了一些后续测试。)
GC.Collect
appears to start the garbage collection in a background thread, and then return immediately. How can I run GC.Collect
synchronously -- i.e., wait for the garbage collection to complete?
This is in the context of NUnit tests. I tried adding the gcConcurrent setting to my test assembly's app.config file, and I tried the same with nunit.exe.config. Neither had any effect -- when I debug, I can still see the finalizer being run on the "GC Finalizer Thread", rather than the thread that called GC.Collect
(NUnit's "TestRunnerThread"), and both threads are running concurrently.
Background: I want my tests to fail if they leak (don't call Dispose on) a particular class. So I've added a finalizer to that class that sets a static wasLeaked
flag; then my test TearDown calls GC.Collect()
and then throws if wasLeaked
is true. But it's not failing deterministically, because when it reads wasLeaked
, the finalizer usually hasn't even been called yet. (It fails some later test instead, after the garbage collection finally finishes.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
终结器在专用的高优先级后台线程上运行。 从您帖子的背景来看,我认为您可以简单地执行
Collect()
将安排任何非根实例进行终结,然后线程将等待终结器线程完成。Finalizers are run on a dedicated, high-priority background thread. From the background in your post, I gather that you can simply do
The
Collect()
will schedule any non-rooted instances for finalization and then the thread will wait for the finalizer thread to complete.您可以使用
GC.RegisterForFullGCNotification
,使用GC.Collect(GC.MaxGeneration)
触发完整收集,然后使用GC.WaitForFullGCComplete
和GC.WaitForPendingFinalizers
方法,但请确保仅在测试中使用此方法,不应将它们用于生产代码。You can use
GC.RegisterForFullGCNotification
, trigger a full collection withGC.Collect(GC.MaxGeneration)
and then theGC.WaitForFullGCComplete
andGC.WaitForPendingFinalizers
methods, but make sure to use this in your tests only, they should not be used for production code.执行此操作的一种更简单/更好的方法可能是使用模拟并检查显式调用 Dispose 的期望。
使用 RhinoMocks 的示例
如果该方法需要创建然后处置对象,那么我将使用并注入一个能够创建模拟对象的工厂类。 下面的示例使用工厂存根,因为它不是我们在此测试中测试的内容。
A easier/better way of doing this may be to use mocking and check an expectation that Dispose was called explicitly.
Example using RhinoMocks
If the method needs to create and then dispose of the object, then I would use and inject a factory class that is able to create the mock object. Example below uses stub on factory as it's not what we are testing for in this test.
无论您是否使用并发 GC,终结器始终在单独的线程上运行。 如果您想确保终结器已运行,请尝试使用
GC.WaitForPendingFinalizers
。Finalizers always run on a separate thread regardless of whether you're using a concurrent GC or not. If you want to ensure that finalizers have been run, try
GC.WaitForPendingFinalizers
instead.