cratosw

内存管理

内存管理

和 C#/.NET 一样,Rust 也强调 memory-safety,用于避免大量与内存访问相关的 漏洞与缺陷。区别在于:Rust 主要在编译期保证内存安全,而不是依赖类似 CLR 的 运行时检查。一个常见例外是数组越界检查,它依然会在运行时发生(无论是 Rust 编译器生成的 机器码还是 .NET JIT 代码)。

和 C# 一样,Rust 也能写 unsafe 代码,并且关键字都叫 unsafe, 用于显式标记“编译器不再保证内存安全”的代码区域。

Rust 没有 GC。内存管理由所有权系统驱动:在 safe Rust 中,值一旦不再被使用, 会在离开作用域时及时释放。编译器通过静态分析执行 ownership 规则,规则不满足时, 直接编译失败。

在 .NET 中,开发者通常无需显式思考“谁拥有这块内存”;GC 会从根对象出发追踪引用并回收。 而 Rust 把所有权、借用、生命周期前置为编码期必答题。这会影响函数签名、类型设计、数据结构 以及并发访问方式。Rust 还能在编译期识别很多潜在的 竞态问题 与数据破坏风险。

Rust 中,一块数据在某一时刻只能有一个所有者。编译器会跟踪生命周期 (见 lifetimes)与所有权流转。所有权转移称为 move

#![allow(dead_code, unused_variables)]

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let a = Point { x: 12, y: 34 }; // a 拥有 Point
    let b = a;                      // 所有权移动到 b
    println!("{}, {}", a.x, a.y);   // 编译错误:a 已失效
}

修正方式如下:

fn main() {
    let a = Point { x: 12, y: 34 };
    let b = a;
    println!("{}, {}", b.x, b.y);   // 使用 b
}   // b 离开作用域时被 drop

main 结束时,ab 都离开作用域,但只有当前持有所有权的 b 会触发释放。

Rust 的 struct 可通过实现 Drop trait 自定义析构行为:

在 C# 中可粗略类比 finalizerIDisposable

  • finalizer 由 GC 在未来某个时刻调用,时间不确定

  • Rust drop 由作用域与生命周期决定,时机确定

  • .NET 里更接近 Rust Drop 语义的是 IDisposable + using 所形成的确定释放

Rust 还有 'static 生命周期,可粗略类比 C# 类型上的静态只读数据的全局存活期。

虽然“单一所有者”看起来很严格,但 Rust 支持共享所有权:Rc<T> 通过引用计数管理共享。 每次 Rc::clone 增加计数,克隆被 drop 时减少计数,降到 0 后释放底层值。

#![allow(dead_code, unused_variables)]

use std::rc::Rc;

struct Point {
    x: i32,
    y: i32,
}

impl Drop for Point {
    fn drop(&mut self) {
        println!("Point dropped!");
    }
}

fn main() {
    let a = Rc::new(Point { x: 12, y: 34 });
    let b = Rc::clone(&a); // 与 b 共享
    println!("a = {}, {}", a.x, a.y);
    println!("b = {}, {}", b.x, b.y);
}

// 输出:
// a = 12, 34
// b = 12, 34
// Point dropped!

要点:

  • Point 实现了 Drop,被销毁时会打印消息
  • 被共享的是 Rc 智能指针,a/b 各自持有一个指针克隆
  • 两个克隆都释放后,引用计数归零,底层 Point 才会被 drop

Rc 不是线程安全的。多线程共享所有权时应使用 Arc

在 .NET 中,值类型通常栈分配、引用类型通常堆分配。Rust 不按“类型类别”决定分配位置: enum / struct 默认都可在栈上;需要堆分配时,可用 Box 装箱。

let stack_point = Point { x: 12, y: 34 };
let heap_point = Box::new(Point { x: 12, y: 34 });

BoxRcArc 都是智能指针,但语义不同:

  • Box 独占所有权
  • Rc 共享所有权(单线程)
  • Arc 共享所有权(线程安全)

最后,C# 里 new 是语言关键字;Rust 里的 new 通常只是约定俗成的关联函数名, 并非语言保留构造语义。

On this page