GC.collect() object reachability
Objects with no more references are not immediately garbage collectable with GC.collect(), howe开发者_如何学运维ver an intermediate call of e.g. new, writeln or Thread.sleep will make the unreferenced object reachable with GC.collect().
import std.stdio;
import core.thread;
import core.memory;
class C
{
string m_str;
this(string s) {this.m_str = s;}
~this() { writeln("Destructor: ",this.m_str); }
}
void main()
{
{
C c1 = new C("c1");
}
{
C c2 = new C("c2");
}
//writeln("Adding this writeln means c2 gets destructed at first GC.collect.");
//Thread.sleep( 1 ); // Similarly this call means c2 gets destructed at first GC.collect.
//int x=0; for (int i=0; i<1000_000_000;++i) x+=2*i; // Takes time, but does not make c2 get destructed at first GC.collect.
GC.collect();
writeln("Running second round GC.collect");
GC.collect();
writeln("Exiting...");
}
The above code returns:
Destructor: c1
Running second round GC.collect Destructor: c2 Exiting...
Can anyone explain this reachability of objects during garbage collection?
I'm not familiar with the details of D's garbage collection, but the general technique is to start from all "root pointers" to figure out which objects are live. When things are compiled down to machine code, this means starting from the function call stack and the CPU registers.
The code above might compile down to something like:
$r0 = new C("c1")
$r0 = new C("c2")
GC.collect()
writeln("Running second round GC.collect")
GC.collect()
writeln("Exiting...")
When the first GC.collect()
there are no more references to the first object (since $r0
was overwritten). And even though the second object isn't used, there's still a pointer to it in $r0
, so the GC conservatively assumes it's reachable. Note that the compiler could conceivably clear out $r0
after variable c2
goes out of scope, but this would make the code run slower.
When the first writeln
call executes, it probably uses register $r0
internally and so it clears the reference to the second object. That's why the second object is reclaimed after the second call to GC.collect()
.
精彩评论