Crates.io | zerogc-simple |
lib.rs | zerogc-simple |
version | 0.2.0-alpha.7 |
source | src |
created_at | 2020-06-22 07:57:53.31785 |
updated_at | 2022-02-14 19:24:18.881127 |
description | Lightweight mark/sweep collector for zerogc. |
homepage | |
repository | https://github.com/DuckLogic/zerogc |
max_upload_size | |
id | 256583 |
size | 112,985 |
[WIP] Zero overhead tracing garbage collection for rust.
Gc<T>
is Copy
and coerces to a reference.Gc<T>
is Copy
.safepoint
call and has no overhead between these calls,Instead of requiring compiler support to track GC roots (like Java/Go), it uses a shadow stack to keep track of GC roots. Collections can only happen at explicit safepoint.
It uses Rust's lifetime system to ensure that freed garbage isn't accessed after a collection. Allocated objects are tied to the lifetime of the garbage collector. A safepoint (potential collection) is treated as a mutation by the borrow checker. Without zerogc (using a Vec or typed-arena), this would invalidate all previously allocated pointers. However, the any 'roots' given to the safepoint are rebound to the new lifetime (via dark magic).
This API aims to be implementation-agnostic,
simply defining the Trace
trait and the interface for safepoints.
Right now the only implementation is zerogc-simple
,
which is a basic mark-sweep collector.
It's relatively fast and lightweight, making it a good default.
It uses fast arena allocation for small objects (optional; on by default) and
falls back to the system allocator for everything else.
In spite of the mark/sweep collector's simplicity, it's reasonably fast and is able to compete with production-quality collectors like Go/Java.
The library is mostly undocumented, since I expect it to change significantly in the future. See the binary-trees example for a basic sample.
This is extremely experimental. It's really uncharted territory in the way it uses the rust borrow checker. It seems to be sound, but I have no way of really knowing for sure.
The simple mark/sweep collector passes basic tests, but it still relies on a lot of unsafe code internally.
Eventually I plan to use this in a language VM, so it needs to be very flexible! I want to support both simple and complex collectors with the same API.
There was previously a copying collector (which worked) 511be539228e7142, but I removed it due to high memory usage.
I was originally inspired to create a safe abstraction for garbage collection by rust gc
but I wanted it to have zero runtime overhead and pointers that are Copy
.
The main problem that the rust-gc solves is finding the 'roots' of garbage collection. His collector uses runtime tracking to maintain a reference to every GC object.
I'm familiar with some JIT implementations, and I know they tend to use safepoints to explicitly control where garbage collections can happen. Normally this is an unsafe operation. All live references on the stack must be given on the stack or use after. Eventually I realized I could use the borrow checker to restrict the usage of roots around safepoints. I was inspired in part by the way indexing uses lifetimes to enforce the validity of indexes.
Our collector only has runtime overhead at specific safepoints, when the shadow-stack is being updated.
Not only is this faster than runtime tracking of every single pointer or conservative collection, but it is more flexible. It paves the way for any combination of generational, incremental, and copying garbage collection.
Since the original rust gc others have attempted to make zero-overhead collectors. I was not aware of this when I started this project.
Gc: Copy
and coerces to a reference.safepoint!
, not memory pressure,
GcSafe
for a type prevents it from having a explicit Drop
implementation.
None of these are fundemental design flaws. They can all be fixed (and should).
Gc<'gc, T>
currently requires T: 'gc