简体   繁体   English

你可以在调用GC.Collect和GC.WaitForPendingFinalizers时遇到死锁吗?

[英]Can you deadlock on calling GC.Collect and GC.WaitForPendingFinalizers?

Given the following: 鉴于以下内容:

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration);

Taking into account multi-threading and Garbage Collection modes, under what circumstances would you get a deadlock on WaitForPendingFinalizers ? 考虑到多线程和垃圾收集模式,在什么情况下你会在WaitForPendingFinalizers遇到死锁?

Note: I am not looking for answers about the reasons why you shouldn't be calling GC.Collect . 注意:我不是在寻找不应该调用GC.Collect的原因的答案。

// causes a deadlock when built with release config and no debugger attached
// building in debug mode and/or attaching the debugger might keep
// badIdea alive for longer, in which case you won't see the deadlock
// unless you explicitly set badIdea to null after calling Monitor.Enter

var badIdea = new BadIdea();
Monitor.Enter(badIdea);

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration);

// ...

public class BadIdea
{
    ~BadIdea()
    {
        lock (this)
        {
            // ...
        }
    }
}

There is famous deadlock on WaitForPendingFinalizers, described by Jeffrey Richter. Jeffrey Richter描述了WaitForPendingFinalizers上有着名的死锁。 It is shown here: http://haacked.com/archive/2005/04/12/neverlockthis.aspx 它显示在这里: http//haacked.com/archive/2005/04/12/neverlockthis.aspx

class MyClass
{

private bool isDisposed = false;

    ~MyClass()
    {
        lock(this)
        {
            if(!isDisposed)
            {
                // ...
            }
        }
    }
}
...
MyClass instance = new MyClass();

Monitor.Enter(instance);
instance = null;

GC.Collect();
GC.WaitForPendingFinalizers();

It is caused by incorrect using of lock(this). 它是由错误使用锁(this)引起的。 Anyway, this is situation when WaitForPendingFinalizers is locked. 无论如何,这是WaitForPendingFinalizers被锁定的情况。

You won't experience any kind of deadlock situation when calling GC.Collect and GC.WaitForPendingFinalizers unless you are accessing managed objects within your Finalize methods. 除非您在Finalize方法中访问托管对象, 否则在调用GC.CollectGC.WaitForPendingFinalizers时不会遇到任何类型的死锁情况。 Calling methods of other objects with a public scope could potentially lead to unpredictable results, including a deadlock. 使用公共范围调用其他对象的方法可能导致不可预测的结果,包括死锁。 The reason is that you're not in total control of those other objects' locking patterns. 原因是您无法完全控制其他对象的锁定模式。 It could be locked by anyone while your finalizer method is trying to access it. 在终结器方法尝试访问它时,任何人都可以锁定它。

Additionally, locking this explicitly in the finalizer is almost guaranteed to cause a deadlock, as LukeH's answer demonstrates. 此外,锁定this在终结明确几乎肯定会导致死锁,因为LukeH的回答证明。 You can read Jeffrey Richter's original article on that here . 你可以在这里阅读杰弗里里希特的原创文章。

In general, you should only be releasing unmanaged resources in your finalizers, which should alleviate any such concerns about deadlocks. 通常,您应该只在终结器中释放非托管资源,这应该可以减轻对死锁的任何担忧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM