8

So I have this simply Bell class that I'm testing garbage collection on:

public class Bell
{
    public void Ring()
    {
        Console.WriteLine("Ding ding");
    }
}

If I run this code segment below, it doesn't get garbage collected

class Program
{
    private static WeakReference reference;

    private static void Main()
    {
        Console.WriteLine("Starting");

        var bell = new Bell();
        reference = new WeakReference(bell);
        bell = null;

        GC.Collect();

        Console.WriteLine("Object still alive: {0}", reference.IsAlive);

        if (reference.Target == null)
        {
            Console.WriteLine("Bell is no more!");
        }
        else
        {
            {
                var theBell = (Bell)reference.Target;
                theBell.Ring();
            }
        }

        Console.ReadLine();
    }
}

If I however only check reference.IsAlive like below, it's garbage collected

class Program
{
    private static WeakReference reference;

    private static void Main()
    {
        Console.WriteLine("Starting");

        var bell = new Bell();
        reference = new WeakReference(bell);
        bell = null;

        GC.Collect();

        Console.WriteLine("Object still alive: {0}", reference.IsAlive);

        Console.ReadLine();
    }
}

Can you guys explain to me how this works?

  • 1
    It works same for me in LINQPad, but when I tried it in VS 2013 it was always collected - debug/release, .NET 3.5, 4.0, 4.5, 4.5.1 – Ondra Feb 12 '15 at 09:18

2 Answers2

6

You're trying to test it with debug mode. GC isn't aggressive in debug mode as it behaves in release mode(with optimize switch turned on). This makes debugging easy, otherwise you'll find strange things while debugging. For example: You may try to inspect the value of already garbage collected variable.

Run the code in release mode and you can see Bell will be GC'd.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
2

That's because of your object type of reference (source)

Represents a weak reference, which references an object while still allowing that object to be reclaimed by garbage collection.

And following could probably explain why two scenarios behave differently (Source)

A weak reference permits the garbage collector to collect the object while still allowing the application to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist. When you use a weak reference, the application can still obtain a strong reference to the object, which prevents it from being collected. However, there is always the risk that the garbage collector will get to the object first before a strong reference is reestablished.

After several runs [With some test cases] : my opinion

The if-else is the key I think. After Writeline, Object is re-refer allowing to get a strong reference before GC clean the object.

Again this phrase is the key

However, there is always the risk that the garbage collector will get to the object first before a strong reference is reestablished.

Kavindu Dodanduwa
  • 12,193
  • 3
  • 33
  • 46
  • 2
    But that is the same in both cases he is asking about... – Justin Harvey Feb 12 '15 at 09:10
  • @Justin Harvey - true. .i would rather keep this as an explanation rather than the correct answer.. – Kavindu Dodanduwa Feb 12 '15 at 09:22
  • 1
    Re-reading now that you have expanded a bit, I am inclined to agree, whilst it is not quite the full answer to the question, it is useful information and helps explain the full answer. – Justin Harvey Feb 12 '15 at 09:24
  • I don't understand how does this answers the question being asked – Sriram Sakthivel Feb 12 '15 at 09:26
  • I tried to update this a bit. IMO may be it's a race condition for GC vs Program instructions to weekreference . I'm also keen to have an exact answer at this point :) – Kavindu Dodanduwa Feb 12 '15 at 09:35
  • 1
    @KcDoD No race whatsoever here. Put a `Sleep(1000)` and see if that's a race. You won't find any difference. When `GC.Collect();` is used, nothing can escape it. That link talks about intrinsic GC, not the forced GC as the case here. – Sriram Sakthivel Feb 12 '15 at 09:38