Dec 12, 2024
2 min read
Rust,

Rust 曾经也有 GC,以及被删除的语法

Rust 早期版本中,有两种主要的指针类型:托管 Box(Managed Box)和所有权 Box(Owned Box)。

没错,早期的 Rust(2013 年以前)确实有”GC”(垃圾回收)功能。为什么后来移除了这个功能呢?这要从 Rust 从被删除的语法说起。

托管和所有权 Box

Rust 早期版本中,有两种主要的指针类型:托管 Box(Managed Box)和所有权 Box(Owned Box)。

托管 Box(Managed Box)

Managed Box 使用 @T 语法表示- 由垃圾回收器管理内存- 允许多个引用指向同一数据- 适用于循环引用的情况。Managed Box 就是分配在堆上的值。

// 这里的 x 只是一个堆上的指针
let x = @10;
// 一个分配到堆上的字符串
let y = @"Hello World";

所有权 Box(Owned Box)

Owned Box 使用 ~T 语法表示,它 基于所有权系统,无需垃圾回收。在值离开作用域时自动释放内存,一次只能有一个所有者。

//这个x也是分配到堆上的指针
let x = ~10;
// 一个分配到堆上的字符串
let y = ~"Hello World"

在 Rust 语言演进的重要阶段,同时出现支持垃圾回收和手动内存管理的尝试。这些尝试也反映了 Rust 在内存管理方面的探索过程。

为什么我们看不到上面的语法了?

直到2013 年的时候,Rust 团队一直寻找简化 Rust 内存管理故事的方法,主要对Rust的内存管理 进行了审视,基本思想是从核心语言中删除垃圾收集并将其归入标准库,并使用最少的语言挂钩集来实现灵活的、可插入的自动内存管理。

在早期,几乎每个 Rust 初学者都会问的最常见问题之一是:

“我什么时候使用托管指针,什么时候使用自有指针?”

或者,更简单地说,

“到处都是这些~@符号是什么?”

他们认为在造成困难的几个原因。其中主要是以下几个部分:

  1. 对于习惯了 Java 这类语言的程序员而言,由于 Java 等语言不区分堆栈和堆,所以他们对堆栈和堆之间的区别理解起来很困难。在使用系统语言工作时,这是一个根本性的难题。如果不把分配的控制权从程序员手中拿走,就很难解决这个问题。但如果这么做,又会损害语言的目标,因为在低级、对性能要求高的编程中,能够精准控制分配在堆栈还是堆上是非常重要的。
  2. 在学习 Rust 语言中的某些概念之前,“~”和“@”符号会使代码显得陌生。因为与 Rust 中的其他标点符号不同,它们不是类 C 语言标准标点符号的一部分,所以会让使用该语言的人感到畏惧。同时提到关键字具有自我记录的好处,而标点符号没有这个优势,所以可以通过切换到关键字来解决这个问题。不过,作者也表示语法的美感因人而异,如果社区更喜欢当前的语法,作者也能接受不改变的情况。
  3. 现在 Rust 中有两个堆,这让初学者在进行内存分配时感到困惑,不知道应该分配到哪个堆中。出现这种情况是因为并发系统遵循 “默认情况下最小化共享” 的理念。但多年来,并发系统一直是库的一部分而非语言本身的一部分,所以这种有两个堆的情况看起来不太合适。
  4. 程序员不知道在某些操作中该使用 “” 还是 “@”,因为不同的操作可以分别用这两个符号进行。并且大家在很长一段时间内都不清楚 “” 和 “@” 哪个会占据主导地位,还对先介绍哪个进行了长时间的争论。随着语言和社区的发展以及编码标准更加稳定,拥有指针 “” 成为了明显的赢家。实际的规则是程序员在所有情况下应优先使用 “” 进行分配,只有在无法准确知道何时应该释放相关对象时才不使用 “~”。

很明显,当前在使用使用“” 还是 “@” 中, “”占了上风。 “@” 曾经被认为会被广泛使用且能为不习惯基于析构函数内存管理和引用的人简化学习曲线,但实际情况是库都使用拥有指针(“”),所以 Rust 程序员必须快速学习“”。一旦学会有效使用“”,就会发现@被降级为边缘角色。“”有诸多优点,如确定性分配和销毁、与标准库交互良好、免于 GC 标记暂停、语义更简单、在涉及向量和字符串时有可附加性以及可跨任务发送。

随着初学者对这种方式熟悉并探索库,他们会了解到更动态的内存管理方法,如使用 GC类型跟踪垃圾收集、Rc 类型进行引用计数、Arc 类型进行线程安全引用计数。通过只在语言中构建 “~”,可以使语言更加固执己见,从而减少混乱。

而且Rust 一个有趣的应用场景是使用在非常低级的编程,甚至可以深入到内核级别。 Java、Ruby 和 JavaScript 等语言,这些语言通过运行时自动、动态地管理内存管理,以牺牲控制和性能来换取便利。剩下的一类软件大部分是用 C 和 C++ 编写的,必须手动管理内存才能实现性能、简单性和/或自托管能力的某种组合。如果Rust 成为只提供一个简单的、全自动的内存管理系统,并且仅当程序员需要它以获得最大性能时才显示安全手动内存管理*的机制,或者能更推动了新兴 Rust 社区的发展。

变动

根据上述考量,最终决定移除使用“@”指针语法的 Managed Box。作为替代方案,使用 Rc(引用计数)和 Arc(原子引用计数)来处理需要共享所有权的情况。与此同时,“~”语法被废弃,其功能则由 Box、Vec、String 等智能指针和集合类型直接承接,这些类型提供了更明确和安全的所有权语义。

总结

也许正是移除了带有垃圾回收器的”@“语法,才让 Rust 如此独特,使其能够以无 GC、内存安全的特色在编程世界中占据重要地位。