2 个稳定版本

1.1.0 2023年7月12日
1.0.0 2023年7月10日

#431 in 内存管理

BSD-2-Clause

670KB
16K SLoC

RSGC

RSGC 是受 Shenandoah 启发的 Rust 写的半保守式 Mark&Sweep 垃圾回收器。

功能

  • 半保守式:可以在线程堆栈和寄存器中找到 GC 指针
  • 支持可变大小的对象(不是 Rust dyn 对象!)如数组和字符串。
  • 轻量级终结器:当对象设置为 `DESTRUCTIBLE` 为 true 时,无法恢复对象。
  • 终结器:有序的终结器,可以恢复对象。
  • 弱引用
  • 弱映射
  • 并发
  • 多线程

基准测试

要运行基准测试,您需要安装 .NET 和 Java,进入 benchmarks/binarytrees 目录并运行 make

架构

分配

分配在区域中发生,如果分配请求大小大于巨型对象阈值,则使用多个区域来分配对象,否则对象在空闲列表中分配。快速路径还包括每个线程的 TLAB 以加快分配速度。

收集周期

RSGC 实质上具有 3 个 GC:并发、退化式和全 GC。并发 GC 由后台控制器线程定期调度。如果在并发 GC 运行时发生过多的分配或 OOM,则切换到退化式 GC。退化式 GC 简单地完成并发 GC 在停止世界阶段的工作。如果发生过多的退化周期,则启动全 GC。全 GC 在停止世界阶段完全执行 GC 周期。

GC 何时开始?

这取决于所选的启发式算法。目前只有 adaptivecompact 可用。

  • 自适应:这些启发式算法将根据收集的吞吐量和延迟调整 GC 阈值。它们还考虑了在突变时间可能发生的分配峰值。
  • 紧凑:当达到特定的分配或空闲阈值时触发的简单启发式算法。

并发性

RSGC 是并发标记-清除。这意味着您需要确保在标记运行时收集器正确地跟踪对象。为此,应在将字段写入对象之后立即调用 Thread::write_barrier


fn foo(thread: &mut Thread, obj: Handle<Obj>, field: Handle<Obj2>) {
    obj.as_mut().field = field;
    thread.write_barrier(obj); // possibly push obj to mark worklist
}

安全点

安全点(Safepoints)是垃圾回收(GC)同步所有线程在某个时间点执行某些无法与运行线程并发执行的操作的唯一方式。要触发安全点,你应该调用 Thread::safepoint


fn some_expensive_func(thread: &mut Thread) {
    thread.safepoint(); // safepoint at entry

    while /* some condition */ {
        // safepoint at loop header
        thread.safepoint();
        /* some expensive code */
    }
}

根化(Rooting)

你不需要以某种方式根化你的对象。GC 能够自动发现栈上的对象。如果你不是所有的对象都位于栈上,可以使用 Heap::add_global_root 添加可遍历的根对象。

依赖项(Dependencies)

~4–14MB
~140K SLoC