Assume I have a C# method like this: (obviously not real code)
byte[] foo()
{
var a = MethodThatReturns500mbObject();
var b = MethodThatReturns200mbObject(a);
byte[] c = MethodThatReturns150mbByteArray(b);
byte[] d = UnwiselyCopyThatHugeArray(c);
return d;
}
As you can guess by the naming, the objects that are returned by these methods are gigantic. Hundreds of megabytes total RAM required by each, although the first two objects are composed of millions of smaller objects instead of one huge chunk like the latter two arrays.
We're going to optimize this into a streaming solution soon, but in the meantime I'd like to make sure that at least we're not preventing GC of the earlier objects while executing code to produce the later objects.
My question is this: will object a
be eligible for GC as soon as MethodThatReturns200mbObject(a) returns? If not, what's the best way to let the GC know that there's a 500MB present waiting for it?
The core of my question is whether the .NET GC's determination of "this object has no references" is smart enough to know that a
cannot be referenced after MethodThatReturns200mbObject(a)
returns. Even though var a
is still theoretically available to later code, a
is not referenced anywhere below the second line of the method. In theory, the compiler could let the GC know that a
is unreferenced. But in practice, I'm not sure how it behaves. Do you know?
This post explains it with examples.
In theory, the compiler could let the GC know that a is unreferenced. But in practice, I'm not sure how it behaves. Do you know?
The correct answer is that it depends on the project configuration whether the object will be eligible for garbage collection at the end of the method. As discussed in When do I need to use GC.KeepAlive? (which also describes the purpose of GC.KeepAlive – in short, it’s a way of referencing or “using” a variable making sure that the optimizer won’t optimize the usage away), the garbage collector might decide to collect objects as soon as they are not usable by any executing code anymore. This can very well happen in situations where it would be valid to access a reference (at compile time), but no such code has been written.
However, when compiling and executing code in Debug-mode, the compiler prevents this from happening to ease debugging. As a result, the correct implementation of our test method includes a preprocessor directive:
Another good read When do I need to use GC.KeepAlive?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With