On Tue, Sep 21, 2021 at 08:17:15PM +0000, eugene via Digitalmars-d-learn wrote: [...] > ```d > void main(string[] args) { > > auto Main = new Main(); > Main.run(); > > auto stopper = new Stopper(); > stopper.run(); > ``` [...] > ```d > void main(string[] args) { > > auto Main = new Main(); > auto stopper = new Stopper(); > > Main.run(); > stopper.run(); > ``` [...] > Everything is Ok now, stopper is not collected soon after start. > So the question is how this innocent looking change can affect GC > behavior so much?...
In the first example, the compiler sees that the lifetime of Main is disjoint from the lifetime of stopper, so it's free to reuse the same stack space (or register(s)) to store both variables. (This is a pretty standard optimization FYI.) So the line `auto stopper = new Stopper();` would overwrite the reference to Main, and the GC would see Main as an unreferenced object and may collect it at any point after the line `Main.run();`. In the second case, since the lifetimes of Main and stopper overlap, the compiler (probably) conservatively assumes that their lifetimes last until the end of the function, and so reserves disjoint places for them on the stack. This does not mean you're 100% safe, however. A sufficiently optimizing compiler may determine that since Main and stopper are independent, it is free to reorder the code such that the two lifetimes are independent, and therefore end up with the same situation as the first example. If Main really depends on the existence of stopper, I'd argue that it really should store a reference to stopper somewhere, so that as long as Main is not unreferenced the GC would not collect stopper. T -- What's an anagram of "BANACH-TARSKI"? BANACH-TARSKI BANACH-TARSKI.