Designing a garbage collector in Rust
manishearth.github.io
manishearth.github.io
In your paragraph about rooting you mention how language support might enable a better implementation (using llvms rooting), but the approach you took sounds very solid. What is the disadvantage of the way you do it now?
Edit: just scrolled through the implementation, it really is as short as the article made it seem, just a couple hundred lines! Now I'm really curious to its performance compared for example with that of Java or Go.
Thanks! Glad you enjoyed it!
> The article makes it seem as though once you had a valid theoretical model implementation was actually easy, is that true?
Rust's affine type system is a huge win here. It has a no-surprises approach to handling data, so it's very easy to practically track roots and all.
So yeah; the implementation is not much more complex than the design above (I don't think I skip any nontrivial part of the design in the post, though that is purely by accident -- I intended to give a sketch of the design and the whole design just happened to come out)
> What is the disadvantage of the way you do it now?
Think of manual rooting as akin to Rc or shared_ptr wrt cost; and the llvm thing is Box/unique_ptr.
Just how the compiler inserts deterministic alloc/free calls with Box, the compiler keeps track of stack based gcthings in llvm. All of the dynamic checks above for rooting become unnecessary; instead at mark time you just pick up the roots from the stack frames. (Note: I haven't looked into the llvm feature; I don't know if it works this way).
Tracking roots is something a compiler is good at. Not so much a runtime.
Regarding Java and Go: I don't know; I haven't tried. But the applications are different -- Java is pervasive, and Go is pervasive with value types and escape analysis (also default concurrent). Rust-gc will probably be horrible at pervasive GCing. Besides, the other two have compiler support so have it much easier when they want to track roots. You can statically insert unconditional calls to `roots.push(var)` if you own the compiler, but as a library author you can have to keep track of many things at runtime to determine if something is a root (which is why llvms solution looks promising to me). In rust-gcs case, rooting status is stored by all the other existing gcptrs, and the status is changed conditionally depending on their states and interaction.
Implementation and performance evaluation of a safe runtime system in Cyclone http://scholar.google.com/citations?view_op=view_citation&hl...
Type-preserving garbage collectors http://scholar.google.com/citations?view_op=view_citation&hl...
One of the useful things with Rust's ownership model is it forces good architectures. I feel like with a GC it's much easier to be "lazy" about who owns something which seems very counter to what I've found interesting and useful in Rust.
Hopefully people heed this advice. My guess is it will not be a problem because most example code (and all of the docs) will not use Gc pervasively.
Being explicit about who owns something makes it much harder to leak things by forgetting to clear references/etc.
(Possibly related: one of the first thing I noted as a student (in architecture) was the fact of the 'beaten path' vs the ideal of the designated path.)
Given that Rc is rarely/never used pervasively; I'm confident that this won't happen.
For those intending to use GC pervasively: Every time you use Gc<bool>; I kill a kitten. Scratch that, I unleash an AbstractKittenKillerProxyFactory on the world :P
Think of the kittens!