MCPcopy Index your code
hub / github.com/DuckLogic/zerogc

github.com/DuckLogic/zerogc @v0.1.4

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.1.4 ↗ · + Follow
342 symbols 704 edges 24 files 48 documented · 14%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

ZeroGc

[WIP] Zero overhead tracing garbage collection for rust.

Features

  1. Easy to use, since Gc<T> is Copy and coerces to a reference.
  2. Absolutely zero overhead when modifying pointers, since Gc<T> is Copy.
  3. Implementation agnostic API
  4. Unsafe code has complete freedom to manipulate garbage collected pointers, and it doesn't need to understand the distinction
  5. Uses rust's lifetime system to ensure all roots are known at explicit safepoints, without any runtime overhead.
  6. Collection can only happen with an explicit safepoint call and has no overhead between these calls,
  7. API supports moving objects (allowing copying/generational GCs)

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.

Status

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.

Motivation

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. It would be unsafe to trust the user to . 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.

Prior Art

Since the original rust gc others have attempted to make zero-overhead collectors. I was not aware of this when I started this project. 1. shifgrethor - This is extremely impressive. It appears to be the only other collector where Gc: Copy and coerces to a reference. - However, the collectors have to support pinning of roots (which we do not) - See this blog post series for more 2. cell-gc - Unfortunately this has a rather clunky interface to Rust code, so it wouldn't be suitable . - They implement a basic List VM as a proof of concept. 3. gc-arena - Ironically the original use case for this collector was a replacement for arena allocation - Like our collector, safepoints are explicitly requested by the user - However instead of attempting to rebind lifetimes, they attempt to use futures to build state machines

Disadvantages

  1. The garbage collector can only run in response to an explicit safepoint!, not memory pressure,
  2. This is a fundamental design limitation.
  3. One can think of this as a feature, since garbage collection can be restricted to specific times and places.
  4. The user must be liberal about inserting safepoins
    • Generally high-level languages which use GCs automatically insert calls to safe points
    • Their safepoints tend to be lower-overhead than ours, so you need to balance the cost/benefit
  5. Unfortunately, implementing GcSafe for a type prevents it from having a explicit Drop implementation.
  6. This is needed to ensure that the destructors don't do bad things, since we don't want to deal with finalizers.
  7. Of course unsafe code isn't bound by this restriction, since it's assumed to behave properly

Extension points exported contracts — how you extend this code

GcSafe (Interface)
Indicates that a type can be safely allocated by a garbage collector. ## Safety Custom destructors must never reference [9 …
src/lib.rs
CollectorPtr (Interface)
An unchecked pointer to a collector [2 implementers]
libs/context/src/collector.rs
DynTrace (Interface)
NOTE: Needs be public for RawCollectorImpl [2 implementers]
libs/simple/src/lib.rs
GcBrand (Interface)
Changes all references to garbage collected objects to match `'new_gc`. This indicates that its safe to transmute to th [6 …
src/lib.rs
Sealed (Interface)
(no doc) [4 implementers]
libs/context/src/state/mod.rs
StaticGcType (Interface)
(no doc) [1 implementers]
libs/simple/src/lib.rs
Trace (Interface)
Indicates that a type can be traced by a garbage collector. This doesn't necessarily mean that the type is safe to allo [14 …
src/lib.rs
RawHandleImpl (Interface)
A [RawCollectorImpl] that supports handles [1 implementers]
libs/context/src/handle.rs

Core symbols most depended-on inside this repo

load
called by 30
libs/context/src/utils.rs
iter
called by 24
libs/simple/src/alloc.rs
get
called by 18
src/cell.rs
clone
called by 18
libs/context/src/handle.rs
manager
called by 16
libs/simple/src/lib.rs
as_ref
called by 15
libs/context/src/collector.rs
store
called by 13
libs/context/src/utils.rs
as_ptr
called by 11
libs/context/src/collector.rs

Shape

Method 216
Class 58
Function 34
Interface 28
Enum 5
Struct 1

Languages

Rust96%
Java2%
Go1%
Python1%

Modules by API surface

libs/simple/src/lib.rs59 symbols
src/lib.rs41 symbols
libs/context/src/collector.rs40 symbols
libs/simple/src/alloc.rs29 symbols
libs/context/src/state/sync.rs26 symbols
libs/context/src/handle.rs23 symbols
libs/derive/src/lib.rs19 symbols
libs/derive/tests/basic.rs18 symbols
libs/context/src/state/nosync.rs17 symbols
libs/context/src/lib.rs17 symbols
libs/context/src/utils.rs10 symbols
src/cell.rs9 symbols

For agents

$ claude mcp add zerogc \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page