3

I am running the code below and the result is totally different when it runs in Release mode. While in Debug mode, it never collects the object of class A and in Reaelse mode it immediately collects the object of class A.

Can someone explain why.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text;

namespace ConsoleApplication2 {
    class Program
    {
        static void Main(string[] args)
        {
            A obj = new A();

            B bobj = obj.objB;

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

            while (bobj.isLive)
            { 
                Console.WriteLine("Is Alive!!");
            }

            Console.WriteLine("Is Dead!!");

            Console.ReadLine();
        }
    }

    class A:IDisposable

    {
        public B objB = new B();

        public A()
        { }

        ~A()
        {
            objB.Dispose();   
        }

        #region IDisposable Members

        public void  Dispose()
        {
            GC.SuppressFinalize(this);
        }

        #endregion


    }
    class B:IDisposable
    {
        public bool isLive = true;

        #region IDisposable Members

        public void  Dispose()
        {
            this.isLive = false;
            GC.SuppressFinalize(this);
        }

        #endregion
    } }
Rik
  • 28,507
  • 14
  • 48
  • 67
MSIL
  • 2,671
  • 5
  • 24
  • 25
  • Also answered here: https://stackoverflow.com/questions/7165353/does-garbage-collection-run-during-debug/55173035#55173035 – James Wilkins Mar 14 '19 at 22:37

3 Answers3

4

In Debug mode, the compiler does not optimize the local variables. Therefore, the reference to A still exists. In Release mode, the compiler optimized the usage so that the reference is thrown away and the object can be collected.

Lucero
  • 59,176
  • 9
  • 122
  • 152
  • That's not the reason. The reference isn't thrown away, it's considered inactive, and that has nothing at all to do with optimization. It's the other way around; the variable can be optimized away from that point as it's inactive. – Guffa Apr 16 '09 at 12:22
  • "Thrown away" may be a bit too simple as explanation, agreed. Still, the reason is correct; there is no strong reference kept in release mode which prevent the GC from collecting the instance. – Lucero Apr 16 '09 at 12:30
  • Because of optimizations in release mode, the reference scope is only valid till its last usage and not the entire block of code it is defined in. What happens in debug mode is clearly stated by Lucero above. – MSIL Jun 19 '09 at 04:27
3

I just found this behavior in my tests. Inserting

obj = null;

right before GC.Collect() should help. I think that is kind of "simulated" optimization.

sko
  • 31
  • 1
  • Please note that this won't work if there is a try-catch clause after invocation of GC.Collect. A better solution would be to create the object in another method so the reference is out of scope when GC runs. – Shocked Dec 16 '15 at 09:28
3

The garbage collector handles variable usage differently in debug mode and release mode.

In release mode the usage of a variable is only where it's actually used. After the last use of the varaible, the object is up for garbage collection.

In debug mode the usage of a varaible is expanded to it's scope. The reason for this is so that the watch window in the debugger can show the value of a variables throughout it's scope.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005