Reputation: 31
class GCTest {
static Object r1;
static void Main() {
r1 = new Object();
Object r2 = new Object();
Object r3 = new Object();
System.GC.Collect(); // what can be reclaimed here ?
r1 = null;
r3.ToString();
System.GC.Collect(); // what can be reclaimed here ?
}
}
// code from - DonBox's Essential .Net
Upvotes: 3
Views: 1589
Reputation: 9495
Upvotes: 0
Reputation: 74382
The GC may collect whichever object for which it can prove that it makes no difference for the application. One way to think about it is the following: objects are allocated forever but the implementation is allowed to reclaim memory as long as it makes sure that you cannot notice it.
In your example, at the first GC.Collect()
, the first object reference has been written to r1
, and r1
is a static variable, thus somehow "permanent". From the point of view of the GC, just about any code could use that static variable, so the GC cannot make sure that the first object will not be used. Therefore it cannot collect it. The second object, on the other hand, is written in a local variable. The local variable is limited to the method code (it disappear when the method exits) and the GC is able to notice that r2
will not be used anymore (the GC only needs to look at the method, not the whole code, so this is part of what the GC can reasonably do). Therefore, the GC may collect the second object (there is no obligation here).
The third object will still be used after the first GC.Collect()
: its ToString()
method is called. Hence the GC should not collect it. However, it is conceivable that the VM notices that this is a true Object
instance (not any other class), inlines the call to ToString()
, and further concludes that the whole ToString()
call is an elaborate way of doing nothing (no visible outcome). As such, the GC might be able to collect the third object and skip the call to ToString()
altogether.
Of course the GC is free not to collect things as well. The whole point of the GC is that it runs "behind the scene", without impacting the code execution (this is not entirely true in presence of finalization, but that's an extra layer of complexity which should not be envisioned until you master the basics).
Wilson's article is indeed a must-read for anybody wishing to understand what garbage collection does.
Upvotes: 2
Reputation: 4489
Try your code with WeakReference and you will see, when these references are alive. Try also to go outside your method. GC only reclaims r1
. WeakReference can give you better insight, when your references go dead.
The response with exception is of course a nonsense. The only exception that can r3.ToString()
rise is null reference exception, but iff r3
is null.
Upvotes: 2
Reputation: 65506
To me it means the first object in a reference chain. ie A refers to B and B to C etc. A is a Root as nothing else refers to it.
At the first one.
r1 Is static and GC test is holding a reference to it so cannot be collected, while r2 can be collected. r3 will be unless you're in a Debugger or GC.KeepAlive is called
At the second one
r1 can be collected as it no longer in scope r2 is already collected And dependent on whether r3 was collected, it may have raised an exception, or will be collected.
Upvotes: 0
Reputation: 72870
At the first line, there are no further references to r2
, so this object could be reclaimed at this point. At the last line, the object created for r1
no longer has a reference, and the local variables r2
and r3
are finished with, so all three objects could be reclaimed at this point. However, this will depend on how it is all compiled.
The three are all root references, as nothing else refers to them. Had r1
been an instance field rather than a static one, then a reference to your GCTest
class would have made the r1
reference not a root reference.
Upvotes: 3