Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Garbage Collection misunderstanding in c#

i have searched on google not getting what i want. i don't know i am right or wrong. look , i have trying to understand GC.Collect() so here is the code..

public class SomePublisher
{
    public event EventHandler SomeEvent;
}

public class SomeSubscriber
{
    public static int Count;

    public SomeSubscriber(SomePublisher publisher)
    {
        publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
    }

    ~SomeSubscriber()
    {
        SomeSubscriber.Count++;
    }

    private void publisher_SomeEvent(object sender, EventArgs e)
    {
        // TODO: something
    }
}

i do this in my main thread..

 SomePublisher publisher = new SomePublisher();

        for (int i = 0; i < 10; i++)
        {
            SomeSubscriber subscriber = new SomeSubscriber(publisher);
            subscriber = null;
        }

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

        Console.WriteLine(SomeSubscriber.Count.ToString());
        Console.ReadLine();

i am getting output 0 but it should bebe 10 according to me because GC.Collect() must have remove class1 objects from memory so class1 destructor must be called so the count must be increased to 10..can any body explain this..

like image 802
loop Avatar asked Jan 13 '23 16:01

loop


1 Answers

(Note also that C# does not have destructors1, it has finalizers. These are very different things, and you should not confuse them.)

The "problem" is on this line:

publisher.SomeEvent += new EventHandler(publisher_SomeEvent);

This creates a delegate targeting the publisher_SomeEvent() method of the particular object instance, and adds this delegate to the invocation list for the publisher.SomeEvent event. This delegate object references the target object, and it is preventing the object from being collected! (This is a good thing -- if you take a delegate to a method on a particular object then you don't want that object being collected until the delegate is no longer referenced.)

This technically isn't a problem at all, but rather is the runtime keeping objects alive that are still referenced.

To illustrate, this is the chain of references:

SomePublisher -+-> EventHandler --> SomeSubscriber
               |
               +-> EventHandler --> SomeSubscriber
               |
               +-> (Eight more...)

You need to do one of two things before calling GC.Collect():

  1. Unsubscribe from the event before releasing each SomePublisher object. This will make both the EventHandler delegate instances and the SomeSubscriber instances they reference eligible for collection.
  2. Set publisher = null;. This will cause the entire object graph to become eligible for collection.

In both cases, this will release all references to the SomeSubscriber objects.


1 Note that the C# specification does call these blocks of code "destructors," but this is a horrible name. Those familiar with garbage-collected languages will be confused by it, as "finalizer" is the widespread term for code that is invoked by the garbage collector when an object is no longer reachable. C++ developers in particular will expect the destructor to be executed at a different time. So yes, C# has something called a "destructor," but it is not a destructor. (Saying something doesn't make it so!)

like image 132
cdhowie Avatar answered Jan 15 '23 07:01

cdhowie