README.md
August 8, 2026 ยท View on GitHub
gc-arena
This repo is home to the gc-arena crate, which provides Rust with garbage
collected arenas and a means of safely interacting with them.
The gc-arena crate, along with its helper crate gc-arena-derive, provides
allocation with safe, incremental, exact, cycle-detecting garbage collection
within a closed "arena".
These garbage collected arenas are safe through the use of three main techniques:
-
The
Collecttrait is used to implement exact tracing. This trait is unsafe and implementing it incorrectly can lead to UB, but the trait can be (and almost always is) safely derived via proc-macro. -
Pointers are branded with a unique generative
'gclifetime that ensures that they cannot escape mutation callbacks or be assigned to the wrong arena. -
"Mutation xor collection" -- Either
Arena::mutateis executing orArena::collectis executing, but never both at the same time. This way, we know that there are no untraceable objects on the stack when we callArena::collect.
See this blog post for an in-depth tour of the crate's design. It is quite dense, but it explains everything necessary to fully understand the machinery used in the included linked list example.
Current status
Basically usable and safe! It is used by the Adobe Flash Player emulator Ruffle for its ActionScript VM as well my own GameMaker compatible compiler / VM fabricator which is used by the game Fields of Mistria.
Collection is implemented using an incremental mark-and-sweep algorithm very
similar to the one in PUC-Rio Lua, and is optimized primarily for low pause
time. During mutation, allocation "debt" is accumulated, and this "debt"
determines the amount of work that the next call to Arena::collect will do.
The pointers held in arenas (spelled Gc<'gc, T>) are zero-cost newtypes around
*const T that implement Copy. No pointer bookkeeping at all is necessary as
Gcs are moved or copied during mutation.
There is robust support for allocating slices, strs, and other DSTs
(Dynamically Sized Types) directly in Gc pointers. Gc pointers to DSTs can
also have either a "fat" or "thin" representation, the second of which reads
pointer metadata from the GC object header.
Use cases and "mutation xor collection"
The "mutation xor collection" design means that Arenae::mutate must return
for collection to be performed, and thus code that uses GC objects cannot
be running while collection takes place. This is not as much of a problem as
it sounds like since there is a built-in mechanism for rooted Gc pointers that
is fairly cheap, and with rooted pointers the crate can be used more from the
"outside" than from within Arena::mutate, but it is still a major limitation
to consider. When used from the "outside" this way, the crate is more like
other garbage collector systems for Rust that primarily use rooted pointers
that are not zero-cost, and Arena::mutate then acts as an "accelerator" for
as-cheap-as-possible pointer manipulation.
Sometimes "mutation xor collection" is not even a problem though! Video games (or programs that are similar to video games) generally want to run VM code that returns once per frame and then also run some garbage collection once per frame. If you are writing a VM that will primarily be used in that way, this crate may be perfect for you! This was the original use case for this crate and what initially formed its design -- writing fast VMs for scripting languages that are used in video games in safe Rust.
Some other notable limitations:
-
Generators (or just plain
async) can be used, with some effort, to overcome the limitation that collection cannot be run while GC code is running. This would be much easier if it were possible to generateCollectimpls for generator state machines, but there is currently no way to do this in Rust nor any planned feature that would enable it. -
This crate is designed for single-threaded use and multiple, independent arenas. It has no support for multi-threaded mutation or collection.
-
There is currently no mechanism for moving allocated objects or heap compaction.
Prior Art
The ideas here are mostly not mine. Much of the user-facing design is borrowed heavily from rust-gc, and the idea of using "generativity" comes from You can't spell trust without Rust. The design of the actual garbage collection system itself borrows heavily from the incremental mark-and-sweep collector in Lua 5.4.
License
Everything in this repository is licensed under either of:
- MIT license LICENSE-MIT or http://opensource.org/licenses/MIT
- Creative Commons CC0 1.0 Universal Public Domain Dedication LICENSE-CC0 or https://creativecommons.org/publicdomain/zero/1.0/
at your option.