Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

Note: I am not looking for answers about the reasons why you shouldn't be calling GC.Collect.

like image 804
Tess Avatar asked Dec 08 '10 10:12

Tess


People also ask

Can we call GC collect method and when to call?

Refrain from calling the GC. Collect method explicitly to reclaim the memory occupied by the objects in your application unless there is a specific reason do so.

Can we call GC collect?

To have the garbage collector consider all objects regardless of their generation, use the version of this method that takes no parameters. To have the garbage collector reclaim objects based on a GCCollectionMode setting, use the GC. Collect(Int32, GCCollectionMode) method overload.

Can we call GC collect in C#?

The C# language is a garbage-collected language. This means that memory that is no longer referenced by your program will be reclaimed and is later reused. With GC. Collect, we force a garbage collection to occur at any time.


2 Answers

// 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)
        {
            // ...
        }
    }
}
like image 67
LukeH Avatar answered Sep 19 '22 13:09

LukeH


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.

like image 40
Alex F Avatar answered Sep 18 '22 13:09

Alex F