栈是编译器帮你自动管理的“临时工位”,堆是程序员或运行时显式申请的“长期仓库”。
下面用 5 个维度把区别拆干净,并给出 Rust / C / Python 的代码片段方便对照。
-
生命周期:谁决定何时回收?
-
栈:编译器根据作用域自动插入“弹栈”指令(进入/离开花括号)。
-
堆:程序员或库/运行时显式释放(C 的
free、C++ 的delete、Rust 的drop、Python 的 GC)。
{
let x = 42; // 栈:离开作用域立即回收
let y = Box::new(42); // 堆:离开作用域时 Drop trait 释放
}
-
性能:分配、访问、缓存
| 操作 | 栈 | 堆 | 备注 |
|---|---|---|---|
| 分配/释放 | O(1) 移动栈指针 | O(allocator) | 堆要查空闲链表 |
| 访问速度 | 连续内存,cache 友好 | 可能跨越页,cache miss 高 | 现代 CPU 预取可缓解 |
| 碎片 | 无 | 有,需要碎片整理 | jemalloc/tcmalloc 降低 |
-
容量与大小限制
-
栈:几 MB 级(Linux 默认 8 MB,Windows 1 MB)。
-
堆:受进程虚拟地址空间或物理内存限制(GB~TB)。
char big[8 * 1024 * 1024]; // 栈溢出 (Linux)
char *big = malloc(8 * 1024 * 1024); // OK,在堆
-
线程模型
-
栈:每个线程独享 1 份,切换线程时切换栈。
-
堆:进程内所有线程共享,需同步(锁或无锁算法)。
-
语言视角:语法糖 & 安全隐患
-
C/C++
-
栈:局部变量;隐患:栈缓冲区溢出。
-
堆:
malloc/free,隐患:UAF、double free。
-
-
Rust
-
栈:默认存放
Copy类型(i32、bool等)。 -
堆:
Box<T>/Vec<T>/String,所有权系统保证“无悬垂”。
-
-
Python / Java / Go
-
一切皆对象 → 除小整数、局部变量外,大部分在堆。
-
GC 负责回收,程序员无感,但有“Stop-The-World”延迟。
-
一张速查表
| 维度 | 栈 (Stack) | 堆 (Heap) |
|---|---|---|
| 分配者 | 编译器 | 程序员 / 运行时 |
| 速度 | 极快 | 相对慢 |
| 容量 | 小 | 大 |
| 生命周期 | 作用域 | 显式或 GC |
| 线程归属 | 每线程私有 | 全线程共享 |
| 碎片 | 无 | 有 |
| 典型错误 | 栈溢出、缓冲区溢出 | 泄漏、UAF、碎片 |
一句话总结
把栈当成“函数调用时的临时便签”,把堆当成“进程级别的共享仓库”;前者靠编译器自动收拾,后者要么靠人、要么靠运行时。
43万+

被折叠的 条评论
为什么被折叠?



