So I know the basics here – an object is eligible for garbage collection when it’s no longer reachable by a root (i.e. a strong reference either from a local variable in a stack frame or a static reference)
The question I have is about this potential optimization where, even if an object is referenced from a local variable, it may be garbage collected at any point in a function where the variable is no longer referenced. First – it appears that existing implementations of C# don’t do this – both 2.0 and 4.0 seem to keep local references “live” until the stack frame is destroyed. But – I’d also like to write code that is still robust if and when garbage collection is optimized in later versions of the CLR.
So – without further ado, here’s some code illustration:
class Foo
{
...
}
class Program
{
public static void fxn1(int blah)
{
...
}
public static void fxn2(Foo foo)
{
...
}
public static int ToInt(Foo foo)
{
...
}
public static void Main()
{
...
Foo foo = new Foo();
fxn2(foo); // I THINK foo may not be GC'ed until fxn2 returns...
// I THINK foo may be GC'ed here, even though CLR2.0 and CLR4.0 don't...
// (experiment shows CLR 2.0 and 4.0 leave foo "live" until Main returns)
fxn2(new Foo()); // I THINK the argument can't be GC'ed until fxn2 returns...
// I KNOW that even CLR2.0 and CLR4.0 will GC the argument after the return...
fxn1( ToInt(new Foo()) ); // I KNOW that new Foo is GC'able even within fxn1...
}
}
So ultimately, the rules for existing CLR’s seem to be:
1. any object is “live” for the duration of a function call for which it is an immediate argument
2. any object is “live” for the duration of a function call if it is referenced by a local stack variable that is not reassigned. (even if the stack variable may not be referenced for several instructions at the end of the function)
However – apparently C# reserves the right to modify (2) so that an object is “live” up until the final use of a reference within a function.
Would this mean:
Foo foo = new Foo();
Foo foo2 = new Foo();
fxn2(foo); // foo is NOT GC'able until fxn1 returns?
// foo IS GC'able from here on? (b/c no further uses of local "foo"?)
fxn2(foo2); // foo2 is NOT GC'able within fxn2 ?
fxn1(ToInt(foo2)); // foo2 IS GC'able within fxn1 ? (existing CLR does not GC foo2)
Is there anything in the ECMA spec which deals w/ garbage collection eligibility in detail?
@M.Babcock – Thank you for the link to the ECMA spec! 8.4 was actually too general, but the answer I was looking for was in 10.9 – and is identical to Java – when a variable can be no longer referenced by any possible future code path, then it is considered eligible for garbage collection – which means that although the existing clr implementation seems to scope local variable lifetime to the stack, there’s no guarantee that third party or future implementations will do so.