The image about rust programming language main features

软件工程领域常面临性能与安全的取舍问题,在软件开发中,选择什么语言,是需要仔细思考权衡的问题, 不同的语言有不同的侧重。

很早诞生的 C/C++ 语言,由开发者自己进行内存管理,由他们自己来申请和释放内存, 拥有很高的性能,但是却容易忘记释放内存,或在复杂场景出现意外导致该释放的内存没有正常释放, 导致出现 内存泄漏悬垂指针 等复杂诡异 bug,程序员的心智负担极大。

后来诞生的像 Java/Golang 等大多数语言,为了解决这个问题,增加了垃圾回收,由运行环境自动释放内存。 这很好的解决了令人难受的内存安全问题,但又带来了性能降低的副作用(Stop-the-World)。

鱼与熊掌真的不可兼得吗!

Rust 语言则通过所有权机制成功的解决了性能与安全问题,既高性能又安全,做到了鱼与熊掌二者兼得。

操作系统内核

操作系统内核是软件世界中最需要安全和性能的地方。传统上,只有 C 和 C++ 能满足这种对底层硬件的极致控制和性能要求。 然而,这也付出了巨大的代价:几十年来,由内存安全问题(如缓冲区溢出、悬垂指针)和数据竞争(并发问题)导致的漏洞和崩溃层出不穷。 据统计,微软和谷歌发现其产品中约 70% 的严重安全漏洞都与内存安全有关。

Rust 的设计目标就是为了在不牺牲性能的前提下,从根本上解决这两个问题。

  1. 核心优势:编译时的内存安全
    • C/C++ 的问题在于,内存管理完全依赖程序员的自觉和经验,一不小心就会出错。
    • Rust 通过其创新的所有权(Ownership)、借用(Borrowing)和生命周期(Lifetimes)系统, 在编译阶段就能检查出绝大多数内存错误。如果你的代码有内存风险,它根本就无法通过编译。 这对于内核这种不允许出错的软件来说,是革命性的。
  2. 无畏并发(Fearless Concurrency)
    • 内核是高度并发的。在 C/C++ 中,编写正确的多线程代码非常困难,数据竞争是家常便饭。
    • Rust 的所有权系统自然地延伸到了多线程领域。它的类型系统(通过 SendSync trait)可以静态地保证线程之间的数据访问是安全的, 在编译时就消除数据竞争。
  3. 零成本抽象(Zero-Cost Abstractions)
    • 内核编程要求不能有不可预测的性能开销,比如垃圾回收(GC)。
    • Rust 和 C++ 一样,提供了强大的高级抽象(如泛型、trait、迭代器),但这些抽象在编译后会被优化掉, 最终生成和手写 C 代码一样高效的机器码,不会带来额外的运行时开销。
  4. 显式的 unsafe 关键字
    • Rust 知道内核编程不可能完全脱离底层操作(比如直接读写硬件寄存器、操作裸指针、调用汇编代码)。
    • 它没有禁止这些操作,而是要求你必须将这些代码块包裹在 unsafe { ... } 中。这相当于你对编译器说:“相信我, 我知道这块代码的风险,并由我来保证它的安全。” 这使得危险代码的范围被清晰地标记和隔离,极大地便于了代码审计和审查。

现实案例

  1. Linux 内核:历史性的接纳
    • 这是一个里程碑事件。从 Linux 6.1 版本开始,Rust 被正式接纳为第二门可用于内核开发的官方语言
    • 目前,它主要被用于编写驱动程序和独立的模块。这样做的好处是,可以用 Rust 编写新的、更安全的代码,同时与庞大的、用 C 写成的内核核心和平共存。
    • 连 Linus Torvalds 本人也从最初的怀疑转变为务实的支持者,他认为 Rust 能在驱动等领域显著提升安全性。
  2. Redox OS:纯 Rust 的操作系统
    • 这是一个完全从零开始、使用 Rust 编写的微内核操作系统。它证明了使用 Rust 构建一个完整、可用的现代操作系统是完全可行的。 从内核到驱动,再到用户空间的应用程序,几乎全部是 Rust。
  3. 科技巨头的推动
    • Google:正在将 Rust 大量用于 Android 系统底层(尤其是在蓝牙、Wi-Fi 等安全敏感的模块)和其下一代操作系统 Fuchsia 中,以减少安全漏洞。
    • Microsoft:正在积极探索用 Rust 重写 Windows 的部分底层组件,微软 Azure 的首席技术官甚至公开表示“是时候停止用 C/C++ 开启新项目了”。
    • Amazon (AWS):开发了基于 Rust 的虚拟化技术(Firecracker),并用 Rust 编写了 Bottlerocket OS,一个专为容器设计的 Linux 发行版。

Rust 所有权机制是 Rust 设计哲学的精髓,它带来了革命性优势(使得程序员写程序时不用考虑手动内存释放和自动垃圾回收, 同时巧妙的解决了 C/C++ 这样需要手动内存释放带来的内存问题和 Java/Golang 这样自动垃圾回收带来的性能开销问题, 还额外获得了一个附带的带有好处的副作用,即 使得多线程安全,有很高的和很安全的并发):

1. “不用考虑手动内存释放” (解决了 C/C++ 的问题)

  • C/C++ 的方式(手动管理): 开发者需要手动调用 malloc/new 来申请内存,并手动调用 free/delete 来释放。这个过程极易出错,导致两大经典问题:
    • 悬垂指针 (Dangling Pointer): 内存已经被释放,但指针仍然指向那片区域,后续使用该指针会导致未定义行为。
    • 内存泄漏 (Memory Leak): 忘记释放内存,导致程序占用的内存越来越多,最终可能耗尽资源。
  • Rust 的方式(所有权): Rust 通过一套严格的规则,在编译时就确定了任何一块内存的生命周期。
    • 规则核心: 每个值都有一个唯一的“所有者”。当所有者离开其作用域(比如函数结束时,局部变量失效)时,它所拥有的值会被自动销毁,内存被自动释放。
    • 效果: 编译器会自动在合适的位置插入释放内存的代码。你作为开发者,完全不需要写 freedelete。编译器帮你完成了这项工作,并且保证了它的正确性,从根源上消除了悬垂指针和内存泄漏。

2. “不用考虑自动垃圾回收” (解决了 Java/Go 的问题)

  • Java/Go 的方式(垃圾回收, GC): 程序运行时,有一个后台的“垃圾回收器”会定期扫描内存,找出不再被引用的对象,然后回收它们。
    • 优点: 开发者基本不用关心内存释放,非常方便。
    • 缺点 (性能开销):
      • 运行时开销: GC 本身需要消耗 CPU 资源。
      • “Stop-the-World” 暂停: 某些 GC 算法在执行时,需要暂停所有应用程序线程,这会导致不可预测的延迟,对于游戏、实时系统等延迟敏感的应用是致命的。
      • 更高的内存占用: 通常需要比实际使用量更多的内存来保证 GC 高效运行。
  • Rust 的方式(所有权): Rust 的内存管理是在编译时完成的。编译出的最终程序包含了所有内存释放的指令,就像一个经验极其丰富的 C++ 程序员手写的代码一样。
    • 效果: 没有运行时开销。程序运行时不需要一个单独的垃圾回收器。内存的释放是确定性的(在变量离开作用域时立即发生),性能表现平稳且可预测。

3. “使得多线程安全,有很高的和很安全的并发”

这正是 Rust 被称为“无畏并发 (Fearless Concurrency)”的原因。

所有权机制天然地解决了并发编程中最常见、最难调试的问题——数据竞争 (Data Race)

  • 数据竞争的定义:
    • 两个或多个线程并发地访问同一块内存。
    • 至少有一个访问是写入操作。
    • 没有使用任何同步机制(如锁)来控制这些访问。
  • Rust 如何在编译时防止数据竞争:
    • 所有权防止不安全的共享: 如果一个线程拥有了某个数据的所有权,其他线程就无法直接访问它,除非所有权被明确地转移。
    • 借用规则确保安全访问:
      • 你可以有多个不可变借用(只读引用 &T),但此时不能有任何可变借用。
      • 你只能有一个可变借用(读写引用 &mut T),此时不能有任何其他借用(无论是可变还是不可变)。
    • SendSync trait: Rust 的类型系统进一步保证,只有那些被标记为可以安全地在线程间“发送”(Send)或“共享”(Sync)的类型,才能用于多线程。如果你试图在线程间共享一个不安全的数据类型,代码将无法通过编译。
  • 效果: 一大类极其复杂的并发 bug 在 Rust 中变成了编译错误。你不需要等到运行时再去祈祷没有写错多线程代码,编译器成为了你最可靠的守护者。一旦代码通过编译,你就有了极高的信心,它不会存在数据竞争问题。

总结:三种内存管理模式的对比

特性 C / C++ (手动管理) Java / Golang (垃圾回收) Rust (所有权系统)
管理方式 程序员手动 malloc/free 运行时垃圾回收器 (GC) 自动回收 编译器在编译时决定,自动插入释放代码
性能开销 运行时开销 (理论性能最高) 运行时开销 (GC 暂停, CPU 消耗) 运行时开销 (与 C/C++ 同级)
安全性 不安全 (悬垂指针, 内存泄漏) 内存安全 (无悬垂指针/泄漏) 内存安全 (在编译时保证)
并发安全 不安全 (极易产生数据竞争) 部分安全 (语言层面防范部分问题, 但仍需手动加锁) 极高安全 (在编译时防止数据竞争)

Rust 通过所有权这个核心机制,巧妙地融合了 C/C++ 的高性能、零开销和 Java/Go 的内存安全、开发便利, 同时还附赠了顶级的并发安全性,创造了一条全新的、被证明非常成功的编程语言设计路径。