kamo/mem/
mod.rs

1//! # Memory management
2//!
3//! This module contains the memory management system. It is based on a
4//! [`Mutator`], which is responsible for allocating and freeing values. The
5//! mutator is used to allocate values on the heap. The mutator is also
6//! responsible for garbage collection. The garbage collection is done by a
7//! mark-and-sweep algorithm.
8//!
9//! The memory management system is based on [`Arena`]s. An arena is a
10//! collection of [`Bucket`]s. A bucket is a collection of [`Slot`]s. A slot is
11//! a container for a value. The mutator allocates values by requesting a new
12//! slot from the arena. For each type that is managed by the mutator an arena
13//! is maintained. The mutator returns a [Pointer] to the slot, which can be
14//! used to access the value. When the mutator is dropped, all values are freed
15//! regardless of whether they are reachable or not.
16//!
17//! It is the responsibility of the user to make sure that the mutator is not
18//! dropped while there are still pointers to values. The mutator does not
19//! maintain a reference count by itself. If it is required to pass the mutator
20//! to multiple functions, it is recommended to wrap the mutator in a
21//! [`MutatorRef`]. This type maintains a reference count and can be used to
22//! safely access the mutator. A [`MutatorRef`] can be created by calling the
23//! [`Mutator::new_ref()`] method.
24//!
25//! The hierarchy of types is as follows:
26//!
27//! - [Mutator] contains [Arena]s.
28//! - [Arena] contains [Bucket]s.
29//! - [Bucket] contains [Slot]s.
30//! - [Slot] contains a value.
31//! - a value is represented by a [Pointer].
32//!
33//! The values must be [Trace]able, which means that they must implement the
34//! [Trace] trait. This trait is used to mark values as reachable. The mutator
35//! will call the [`Trace::trace()`] method on all values that are reachable.
36//! This method must add all reachable values, which are reachable from this
37//! value, to the list of reachable values. This is done iteratively until all
38//! reachable values are traced. The reachable values are wrapped in a [Root]
39//! and are stored in a vector of pending values.
40//!
41//! When all reachable values are traced, the mutator will free all values that
42//! are not reachable. This is done by by the [`Arena::sweep()`] method. This
43//! method will iterate over all buckets and free all slots that are not marked.
44//!
45//! A value is reachable if it is a root, or if it is reachable from a root.
46//! Roots are [Slot]s that are locked. This means that they are not freed by the
47//! mutator as long as they hold a lock. The mutator will lock a slot when it is
48//! returned to the user in a [`Pointer`]. Slots get unlocked when they are
49//! added to a [`Pair`](crate::value::Pair) or [`Vector`](crate::value::Vector).
50//! These types may have cycles. If they would not unlock the slots, the slots
51//! would never be freed. This mitigates the problem of cycles with reference
52//! counting.
53
54mod arena;
55pub use arena::Arena;
56
57mod bucket;
58pub use bucket::Bucket;
59
60mod mutator;
61pub use mutator::*;
62
63mod pointer;
64pub use pointer::Pointer;
65
66mod slot;
67pub use slot::Slot;
68
69mod stats;
70pub use stats::Stats;
71
72mod trace;
73pub use trace::{Root, ToRoot, Trace};
74
75/// The target passed to the logger.
76pub const TARGET: &str = "kamo::mem";