This is a question I was asked at my interview recently: Which 'Random' object(s) would get collected during the 'GC.Collect()' call?
String a = new Random().Next(0, 1) ==1 ? "Whatever 1" : "Whatever 2";
String b = new WeakReference(new Random()).Target.Next(0, 1) == 1 ?
"Whatever 1" : "Whatever 2";
GC.Collect();
I answered that this is an implementation-specific question and it highly depends on the GC
implementation and the corresponding weak reference semantics. As far as I know, C# specification doesn't provide exact description of what GC.Collect
should do and how should the weak references be handled.
However, my interviewer wanted to hear something else.
Both Random()
instances and the WeakReference
are eligible for collection:
Random
was not stored in a local, let alone a local that is later read.Random
was passed to a WeakReference
, so would be OK to collect anyway, but the WeakReference
itself is not held anywhere, so that too is eligible for collection.None of the strings are (there are only 2 string instances here, not 4, even if every possible code path was reached): because they are literals in the c# code, they are interned once they exist.
It is true that this is implementation (and compiler) dependant. If all this is in the same method you cannot know which objects are still on the stack. Since objects on the stack are still referenced they wouldn't be collectible.
What the interviewer wanted you most likely to do is to check which objects are still reachable at the call of GC.Collect assuming a "perfect" implementation which discards everything as soon as possible.
However, my interviewer wanted to hear something else.
I expect they wanted to hear an answer like the one Marc Gravell has posted here but that is based upon an over-simplified model of how garbage collected virtual machines work that bears no resemblance to reality.
For example, the call to GC.Collect
might get tail call optimized in which case there are no global roots so all heap-allocated blocks get collected. Or the compiler might create a new entry on the stack frame for every temporary (not just variables in the source code) which keeps everything reachable and nothing gets collected. Or the compiler might swap the order of the creation of the strings a
and b
and collect the Random
object referred to by the WeakReference
before the Target
method is invoked causing a null
reference exception so the other Random
is never even allocated.
GC.Collect is like in Java equivalent to System.gc()
It "recommends" to check for null values to delete them. You can't really depend on this feature since it's really automatic unlike C++.
Hope it helps!
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