深入理解 Rust 的内存模型:变量、值与指针

文章目录

    • 变量、值与指针
      • [与 C++ 对比](#与 C++ 对比)
    • 高层与低层的变量模型
      • [Rust 高层模型(High-level model)](#Rust 高层模型(High-level model))
      • [Rust 低层模型(Low-level model)](#Rust 低层模型(Low-level model))
      • [与 C++ 对比](#与 C++ 对比)
    • 三大内存区域
      • [1. 栈(Stack)](#1. 栈(Stack))
      • [2. 堆(Heap)](#2. 堆(Heap))
      • [3. 静态内存(Static Memory)](#3. 静态内存(Static Memory))
    • 小结

Rust 以"内存安全"著称,但想真正写出高效、安全的 Rust 代码,就必须理解它背后的内存模型。本篇文章将带你从 变量、值与指针 的概念出发,逐步理解 栈(stack)、堆(heap)和静态内存(static memory) ,以及 Rust 的核心机制------所有权、借用和生命周期 。同时我们还会结合 C++ 的内存模型 做详细对比,方便已经熟悉 C++ 的读者更快地建立对应理解。


变量、值与指针

在 Rust 中:

  • 值(Value) :类型与具体数据的组合。例如,6u8 是一个 u8 类型的值,它在内存中的表示是字节 0x06"Hello world" 是字符串值,它的底层表示是 UTF-8 字节序列。
    • 这里的概念和C++中的字面值是类似的,而 Hello world这种字符串,Rust的类型是 &str,和C++中的 const char* 是类似的
  • 变量(Variable):是一个"命名的位置",用来存储值。变量通常存放在栈上。
  • 指针(Pointer) :保存某个内存地址的值,可以解引用访问其指向的数据。Rust 的引用(&T&mut T)本质上就是指针。
rust 复制代码
let x = 42;
let y = 43;
let var1 = &x;
let mut var2 = &x;
var2 = &y;

这里:

  • 值有四个:4243x 的地址、y 的地址。
  • 变量有四个:x, y, var1, var2

与 C++ 对比

在 C++ 中:

  • :表现形式类似,例如 int x = 42; 中,42 就是值,存放在 x 里。

  • 变量:C++ 的变量和 Rust 类似,通常存储在栈上。但 C++ 不会在编译器层面禁止未初始化使用,例如:

    cpp 复制代码
    int a;  // 未初始化
    std::cout << a; // 未定义行为(UB)

    Rust 则会强制报错,避免 UB。

  • 指针与引用

    • C++ 引用(int&)类似 Rust 的 &T,但 C++ 允许把引用绑定到临时对象上,容易导致悬垂引用;Rust 编译期禁止此类情况。
    • C++ 指针(int*)则与 Rust 的原始指针(*const T, *mut T)接近,需要开发者自己保证安全性。

高层与低层的变量模型

Rust 高层模型(High-level model)

  • 把变量看作值的"名字"。
  • 值的使用抽象为 数据流(flow),一旦值被移动,数据流断开,变量失效。
  • 编译器借用检查器会验证是否存在非法的数据流。

Rust 低层模型(Low-level model)

  • 把变量看作一块内存槽。
  • 赋值覆盖旧数据,引用则是内存的地址。

与 C++ 对比

  • C++ 更接近低层模型:变量就是一块内存,指针/引用直接操作地址。编译器不会阻止危险操作。
  • 在高层抽象上,C++ 缺乏 Rust 那样的"所有权"和"借用检查器"。程序员需要依靠编码规范、智能指针(std::unique_ptr, std::shared_ptr)或工具(如 ASan, Valgrind)来避免内存错误。

示例对比:

cpp 复制代码
int* p = nullptr;
*p = 42; // 未定义行为:空指针解引用

Rust 中:

rust 复制代码
let p: *mut i32 = std::ptr::null_mut();
unsafe {
    *p = 42; // 编译器要求 unsafe 块,显式提示风险
}

Rust 把危险操作显式隔离,C++ 则允许直接执行。


三大内存区域

1. 栈(Stack)

  • Rust:函数调用分配栈帧,局部变量生命周期受作用域限制。

  • C++:相同机制,但 C++ 不会禁止返回局部变量的引用:

    cpp 复制代码
    int& foo() {
        int x = 42;
        return x; // 返回悬垂引用,UB
    }

    Rust:

    rust 复制代码
    fn foo() -> &i32 {
        let x = 42;
        &x // 编译错误:借用不满足生命周期
    }

2. 堆(Heap)

  • Rust:通过 Box<T>Vec<T> 等安全抽象分配,释放由所有权系统自动管理。

  • C++:需要手动 new/delete,或使用智能指针:

    cpp 复制代码
    auto p = std::make_unique<int>(42); // 自动释放

    Rust 的 Box<T> 类似 unique_ptr,但由编译器强制约束,避免误用。

3. 静态内存(Static Memory)

  • Rust:static 变量在程序整个运行期存在,'static 生命周期显式建模。
  • C++:全局变量、静态变量在整个程序运行期间存在,但缺乏生命周期建模,容易导致初始化顺序问题(static initialization order fiasco)。

小结

Rust 的内存安全性来自于编译期的严格规则,而 C++ 则更多依赖程序员经验:

特性 Rust C++
未初始化变量 编译时报错 运行时 UB
指针安全 引用/借用受检查,原始指针需 unsafe 任意指针操作,易出错
所有权 强制存在,编译器跟踪 无,需靠约定或智能指针
生命周期 类型系统显式建模 无,需人工推理
内存回收 RAII + 编译器保证 RAII,但需谨慎设计

可以看到,Rust 在很多地方对 C++ 进行了"强制收紧",牺牲部分灵活性换取编译期的安全性。对于熟悉 C++ 的开发者,可以把 Rust 看作是"有更强类型约束和更严格规则的现代 C++"。

相关推荐
无限进步_2 小时前
【C语言】寻找数组中唯一不重复的元素
c语言·开发语言·算法
A阳俊yi2 小时前
Spring——事件机制
java·后端·spring
Fency咖啡3 小时前
Spring进阶 - SpringMVC实现原理(二)DispatcherServlet处理请求的过程
java·后端·spring·mvc
m0_651593913 小时前
位置透明性、Spring Cloud Gateway与reactor响应式编程的关系
java·spring cloud·系统架构·gateway
玉树临风江流儿4 小时前
Cmake使用CPack实现打包
java·服务器·前端
yunmi_4 小时前
微服务,Spring Cloud 和 Eureka:服务发现工具
java·spring boot·spring cloud·微服务·eureka·架构·服务发现
一叶飘零_sweeeet4 小时前
从 0 到 PB 级存储:MinIO 分布式文件系统实战指南与架构解密
java·架构·大文件存储
Dest1ny-安全4 小时前
Java代码审计-Servlet基础(1)
java·python·servlet
好开心啊没烦恼4 小时前
Python数据分析:使用爬虫从网页、社交媒体平台、论坛等公开资源提取中文和英文人名。
开发语言·爬虫·python·数据挖掘·数据分析