Search code examples
c#.netcomgarbage-collectioncom-interop

Is this COM object subject to garbage collection?


I'm using a COM object from .NET using interop. The object basically fetch data from socket and fire some events for .NET layer to process. However, after a while, the COM object stops firing events which revealed later to be because it's collected by GC.

The structure of source code is similar to this one below:

static void Main(string[] args)
{
    MyEventGen gen = new MyEventGen();
    WeakReference wr = new WeakReference(gen);
    gen.ReceiveDataArray += 
            new _IMyEventGenEvents_ReceiveDataArrayEventHandler(gen_ReceiveDataArray);
    while (true)
    {
        Thread.Sleep(1000);
        Console.WriteLine(wr.IsAlive);
    }
}

static void gen_ReceiveDataArray(ref Array indices, ref Array values)
{
    // do nothing
}

alt text

What I know so far:

  • From what I understand, object gen shouldn't be garbage-collected in any way. Since the object is still active in the Main scope. But the result so far shows that the object was collected by GC.

  • The object is only garbage-collected when built as Release and run without debugging. Running the Debug builds / running both modes under debugger are fine.

  • The program will print the first "False" precisely after the first Gen #0 Collection.

  • By accessing the object in the while loop, e.g. Console.WriteLine(gen.ToString()) , prevent it from being GC'd!

  • By adding another static field of Program class to keep its reference also prevent it from GC'd.

  • Trying with different load of data, I found that GC only collects the object when Private Bytes reach over the threshold of ~ 3X MBs.

  • Checking with CLRProfiler, mentioned object was GC'd as suspected.

Have I missed some important .NET GC's concepts? Is it possible to obtain the reason for object being GC'd? Is this, possibly, a known GC bug?

I'm using VS 2008 + .NET 3.5 SP1. Appreciate your thoughts. Thanks!


Solution

  • No need to use a COM object to reproduce this. Consider the following:

    public class MyEventGen
    {
        public event Action ReceiveDataArray;
    }
    
    class Program
    {
        public static void Main()
        {
            var gen = new MyEventGen();
            var wr = new WeakReference(gen);
            // this is the last time we access the 
            // gen instance in this scope so after this line it
            // is eligible for garbage collection
            gen.ReceiveDataArray += new Action(gen_ReceiveDataArray);
    
            // run the collector
            GC.Collect();
            while (true)
            {
                Thread.Sleep(1000);
                Console.WriteLine(wr.IsAlive);
            }
        }
    
        static void gen_ReceiveDataArray()
        {
        }
    }
    

    Run it in Release mode and it will exhibit the same behavior. The gen object falls out of scope and is garbage collected because there is nothing to keep it alive during the execution of the loop.