Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting reference type object in inner scope has no effect on garbage collection: True or False?

I have been reading the Garbage Collection chapter from Jeffrey Richter's fine book, "CLR via C#". There, he illustrated an example of how the GC conceptually works (how roots are marked) by referring to a disassembly listing of native code emitted from the JIT compiler. From that example, it occurred to me that nesting reference types in scope seems to have ZERO effect on expediting the garbage collection of the nested variable. I wonder if I am understanding this correctly. In any case, consider these 2 versions of code:

A) Nesting a reference type variable (y) in an inner scope:

namespace scope
{
    class A { public void foo() { } }
    class Program
    {
        static void Main(string[] args)
        {
            A x = new A();
            x.foo();
            {
                A y = new A();
                y.foo();
            }
        }
    }
}

B) Same as above, except that x and y are in the same scope.

namespace scope
{
    class A { public void foo() { } }
    class Program
    {
        static void Main(string[] args)
        {
            A x = new A();
            x.foo();

            A y = new A();
            y.foo();
        }
    }
}

Out of curiosity, I checked the generated IL code for both versions, and they are the SAME!

Q1: So, this seems to imply that indeed, scoping doesn't expedite garbage collection in any way. Is this correct? (Note: I know about the "using" statement - but I'm only curious about the behaviour on the GC of "plain old scoping" as illustrated in the 2 examples above.)

Q2: If the answer to Q1 is "True", then I am utterly perplexed by how a "Object Lifetime is Not Determined by Scope" situation can possibly happen, as described here: http://www.curly-brace.com/favorite.html

like image 743
mobbi Avatar asked Dec 04 '22 12:12

mobbi


1 Answers

Garbage collection partly depends on whether you're running in the debugger or not. I'll assume we're not.

It can actually be much more aggressive than you think. For example:

object o = new object();
Console.WriteLine(o);   
Console.WriteLine("hi");
o = new object();

The object can be garbage collected immediately after the second line - i.e. long before the variable o exits scope. This would also be true without the final line.

In other words, scoping doesn't expedite garbage collection - because the GC is already smarter than you might think.

In fact, the garbage collector can be even more aggressive. Consider this code:

Foo f = new Foo();
f.SomeMethod();
Console.WriteLine("Hello");

where Foo looks like this:

public class Foo
{
    int x = 10;

    public void SomeMethod()
    {
        Console.WriteLine(x);
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine("Hello");
            Thread.Sleep(100);
        }
    }
}

In theory, the garbage collector can collect the Foo object while SomeMethod is running so long as it's gone past the first line, where it actually reads from x. If Foo had a finalizer, you could have the finalizer running in one thread while SomeMethod was running in another. Scary stuff.

like image 103
Jon Skeet Avatar answered Dec 06 '22 02:12

Jon Skeet