开发者

Can you deadlock on calling GC.Collect and GC.WaitForPendingFinalizers?

开发者 https://www.devze.com 2023-01-29 05:18 出处:网络
Given the following: GC.Collect(GC.MaxGeneration); GC.WaitForPending开发者_Go百科Finalizers(); GC.Collect(GC.MaxGeneration);

Given the following:

GC.Collect(GC.MaxGeneration);
GC.WaitForPending开发者_Go百科Finalizers();
GC.Collect(GC.MaxGeneration);

Taking into account multi-threading and Garbage Collection modes, under what circumstances would you get a deadlock on WaitForPendingFinalizers?

Note: I am not looking for answers about the reasons why you shouldn't be calling 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. It is shown here: 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). Anyway, this is situation when WaitForPendingFinalizers is locked.


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. 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. 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消