内存本质:从比特到指针
原理
DRAM 每个位元为 1T1C(1 transistor + 1 capacitor),电容充电=1,放电=0。因电容漏电需刷新(~64ms 周期)。SRAM 使用 6T 触发器存储,无需刷新,延迟极低(~1ns),用于 CPU 缓存。
内存层次结构:
| 层级 | 技术 | 大小 | 延迟 | Rust 对应 |
|---|---|---|---|---|
| 寄存器 | 触发器 | ~1KB | 0.3ns | 局部变量 |
| L1 缓存 | SRAM | 32KB | 1ns | 热数据 |
| L2 缓存 | SRAM | 256KB | 4ns | 当前工作集 |
| L3 缓存 | SRAM | 8-32MB | 12ns | 跨核共享 |
| 主存 | DRAM | GB | 100ns | Vec 堆分配 |
| 磁盘 | NAND | TB | 10-100μs | File::read |
虚拟内存通过 MMU 将虚拟地址转为物理地址,页表为 4 级结构(x86_64 使用 48 位有效 VA)。TLB 是 MMU 内部缓存,命中则转换零开销,未命中需 4 次内存读(~400ns)。
Rust 启示:Vec 连续内存使 CPU 预取器有效利用缓存行(64B),LinkedList 因随机指针追逐导致 TLB 抖动和缓存未命中。
语法
Rust 内存操作
use std::mem;
let v: Vec<i32> = vec![1, 2, 3];
println!("size: {}", mem::size_of::<Vec<i32>>()); // 24 (ptr+len+cap)
println!("align: {}", mem::align_of::<i32>()); // 4
// 栈上固定大小
let arr: [i32; 3] = [1, 2, 3];
// 堆上通过 Box 分配
let b: Box<i32> = Box::new(42);
let raw: *const i32 = &*b; // 获取底层指针内存布局
| 类型 | 栈大小 | 堆数据 | Copy? |
|---|---|---|---|
i32 | 4B | 无 | 是 |
&[T] | 16B (ptr+len) | 在引用对象上 | 是 |
String | 24B (ptr+len+cap) | UTF-8 字节 | 否 |
Vec<T> | 24B (ptr+len+cap) | T 数组 | 否 |
Box<T> | 8B (ptr) | T | 否 |
dyn Trait | 16B (data+vtable) | 取决于实现 | 否 |
实践
力扣问题
力扣: 力扣斐波那契题 — 注意内存消耗
fn fib(n: u32) -> u64 {
let mut a = 0u64;
let mut b = 1u64;
for _ in 0..n { let t = b; b = a + b; a = t; }
a
}AI 自检
- x86_64 虚拟地址为何只用 48 位而非 64 位?剩余 16 位的作用?
Vec连续内存为何比LinkedList高效?从缓存行(64B)和 TLB 角度解释。