Program crash: GC destroys an object unexpectedly

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Sep 21 20:42:12 UTC 2021


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.


More information about the Digitalmars-d-learn mailing list