这是一系列介绍编写两个 Rust crate 的不同设计决策的文章中的第一篇,两个 crate 分别是:
Rust 和垃圾收集
Rust 目前没有“真正的”垃圾收集(带循环检测),通常将Rc
和Arc
视为一种无循环检测的垃圾收集形式。gc-arena
是将带有这种垃圾收集指针的 Rust 作为库进行改造的尝试。piccolo
需要一个垃圾收集器,且要求垃圾收集指针为零成本普通指针,运行时大部分需内存安全,现有设计无法满足这些要求,于是gc-arena
诞生,其采用类似 PUC-Rio Lua 的增量收集器。
跟踪和内部可变性
为 Rust 设计带有安全接口的跟踪垃圾收集库具有挑战性,主要围绕正确跟踪持有管理(垃圾收集)指针的值以及确定垃圾收集器“根”的集合等问题。通过示例逐步构建双链表数据结构来探讨这些问题及gc-arena
的解决方案:
- 定义双链表节点
Node
,其包含垃圾收集指针Gc
,通过Collect
trait 确保可追溯性,unsafe
实现该 trait 时要确保每个可达指针都被跟踪,可通过 proc-macro 安全实现。 - 由于对象可能包含循环引用,
Drop
trait 会导致问题,gc-arena
通过禁止Drop
impl 来解决,内部使用MustNotImplDrop
trait 实现。 gc-arena
是增量收集器,存在新问题,如用户在增量跟踪操作中修改已跟踪对象可能导致悬空指针,gc-arena
通过Collect
trait 和“颜色不变量”来保护,内部可变性类型不能直接实现Collect
,需使用gc-arena
提供的版本并遵循写屏障契约。
使用生成性查找 GC 根
Rust 借用检查器的一个意外特性引入了“生成性”,可用于垃圾收集。gc-arena
利用此特性,通过'gc
生命周期标记所有垃圾收集值,控制指针生命周期。“竞技场”在系统编程中用于分配具有相同生命周期的内存,gc-arena
中的“竞技场”也有类似含义,通过Gc
指针和PhantomData
类型控制指针,Arena
类型参数化于根类型R
,通过Arena::mutate
方法控制对竞技场的访问,利用 Higher Rank Trait Bounds(HRTBs)确保回调在任何'gc
选择下都有效,从而证明安全垃圾收集的属性。
生命周期投影
定义Arena
本身是最后一个难题,需要一种能在不同'gc
生命周期间进行替换的类型,类似 GAT。gc-arena
未使用 GAT 定义根类型,而是使用带有常规生命周期参数的 trait 和 trait 绑定,通过Rootable!
宏滥用 trait 对象来实现,无需为每个新的Arena
类型声明新类型,每个Rootable!
调用都指向相同类型。
最后给出一个双链表的完整工作示例,展示gc-arena
的各个部分如何协同工作。
总结:gc-arena
是一个为 Rust 配备增量垃圾收集的库,通过一系列技术解决了垃圾收集中的各种问题,但其使用具有较高的认知和可用性开销,未来将进一步讨论其改进方向。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。