page
page

Reputation: 41

Does keeping a reference to an object as a member prevent collection?

Consider the following code, where class A is responsible for managing native data. A pointer to that data is passed to a class B, so I need that A is not collected while B is in use:

class A
{
    public A(string n)
    {
        _n = n;
        _p = IntPtr.Zero; //acquire native resource
    }

    public IntPtr GetP()
    {
        return _p;
    }

    ~A()
    {
        Console.WriteLine("Free native resource {0}", _n);
    }

    string _n;
    IntPtr _p;
};

class B
{
    public B(IntPtr p)
    {
        _p = p;
    }

    public B(IntPtr p, Object o)
    {
        _p = p;
        _o = o;
    }

    public IntPtr GetP()
    {
        return _p;
    }

    IntPtr _p;
    Object _o;
};

If I don't hold a reference to 'a' from 'b', 'a' gets collected immediately as expected, which leaves me with a pointer to invalid data (at least in visual studio, the gc in mono is not so eager):

static void Main(string[] args)
{
    var a = new A("a");
    var b = new B(a.GetP());
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Console.WriteLine("b._p: {0}", b.GetP());
}

Output:
Free native resource a
b._p: 0

But if I hold a reference to 'a' from 'b', 'a' is not freed until exit, even though 'a' is not used later on:

static void Main(string[] args)
{
    var a = new A("a");
    var b = new B(a.GetP(), a);
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Console.WriteLine("b._p: {0}", b.GetP());
}

Output:
b._p: 0
Free native resource a

So my question is: in this second case, is 'a' guaranteed by spec to be alive while 'b' is not collected, or is this behavior implementation dependent? If the latter, how would I go about keeping it alive? I've seen several similar questions but I found no definitive answer for it.

Upvotes: 0

Views: 129

Answers (1)

Thomas Levesque
Thomas Levesque

Reputation: 292405

So my question is: in this second case, is 'a' guaranteed by spec to be alive while 'b' is not collected,

Yes. If b has a reference to a and is not collected, a will not be collected either.

Upvotes: 5

Related Questions