使用 MMTk 向我们基于 Rust 的解释器添加垃圾回收功能

这是一篇关于垃圾收集框架MMTk以及将其实现到基于 Rust 的解释器中的博客文章。

  • 介绍:作者为进行博士研究,在 Rust 中优化 Smalltalk 语言的解释器性能,之前使用智能指针Rc<RefCell<T>>进行内存管理,现在改用 MMTk 进行追踪式垃圾收集,性能提升约两倍,但这需要对解释器进行大量重写。
  • 引用计数:现有简单方法:Rust 指针类型有标准引用&T、原始指针*const T和智能指针Box<T>Rc<T>RefCell<T>等。之前使用Rc<RefCell<T>>处理Class对象的指针,虽能解决共享所有权问题,但访问指针速度慢。
  • 追踪式垃圾收集:这是另一种自动内存管理方式,通过遍历对象图确定哪些对象应被丢弃,在内存不足时停止世界(停止代码运行)进行安全追踪。现实中垃圾收集是复杂领域,我们的性能提升主要来自直接管理自己的堆,而非复杂的垃圾收集算法。
  • GC 很难:离开简单的引用计数方法后,实现垃圾收集非常困难,包括内存分配器、垃圾收集算法和内存扫描等部分都需要稳定,且调试困难,容易出现各种问题,因此需要一个语言无关的框架来简化管理。
  • MMTk 概述:MMTk 项目自 2004 年起存在,通过其 API 可将多种预先存在的垃圾收集算法(如标记清扫、半空间等)或创建自己的算法引入虚拟机,且能在多种语言中快速运行,作者选择 MMTk 是因其高性能、可轻松切换 GC 策略、无需自己实现 GC 以及用 Rust 编写等原因。
  • 实现:新的指针类型:将指针表示从Rc<RefCell<T>>改为包装原始指针的Gc<T>,虽放弃了 Rust 的安全保证,但通过实现Deref/DerefMut使其能像普通引用一样访问底层数据,还通过debug_assert_valid_heap_ptr宏检查指针有效性。
  • 实现:使用 MMTk:通过创建 MMTk 实例和声明Mutator等操作与 MMTk 交互,实现垃圾收集的各个功能,如分配内存、扫描对象图等,还介绍了如何处理不同类型的对象和值。
  • 扫描:通过VMScanningscan_roots_in_mutator_thread函数告诉 MMTk 对象图的根,根以SOMSlot类型报告,scan_object函数负责扫描对象及其子对象,处理各种类型的对象,还介绍了如何处理值的表示和RefValueSlot类型。
  • 移动收集器:三大最严重错误:移动收集器比非移动收集器更复杂,引入更多错误,如复制数据不正确、忘记扫描栈变量、一个难以捉摸的在发布版本中才出现的崩溃错误等,这些错误让作者意识到 Rust 对移动 GC 的优化可能存在问题。
  • 重要安全声明及技术免责声明:作者的解释器目前设计存在问题,需要修改 API,还提到解释器存在一些技术限制,如未明确进行终结处理、Rust 堆上的数据不能引用Gc<T>指针、解释器为单线程等。
  • 结论:总结了垃圾收集的相关内容,包括 MMTk 的优点和使用方法,以及自己实现过程中的经验和教训,感谢相关人员的帮助,希望对其他开发者有帮助。
阅读 8
0 条评论