JAVA八股文第二章(栈(Stack)与堆(Heap))

Java 中栈(Stack)与堆(Heap)的区别详解(面试高频)

在学习 JVM 内存模型时,栈(Stack)和堆(Heap)是最核心、最容易混淆的两个概念。很多人只停留在"栈存变量、堆存对象"的层面,但这远远不够。

本文从原理 + 执行过程 + 面试角度,彻底讲清楚两者的区别。


一、先给出一句话结论

text 复制代码
栈:负责方法执行(运行过程)
堆:负责存储对象(数据本身)

二、栈(Stack)是什么?

👉 本质

栈是线程私有的,用来管理方法调用和执行过程


👉 工作方式

text 复制代码
方法调用 → 入栈
方法执行结束 → 出栈

每个方法在执行时,都会创建一个栈帧(Stack Frame)


👉 栈帧结构

一个栈帧包含:

  • 局部变量表(存变量值 / 引用)
  • 操作数栈(用于计算)
  • 动态链接(连接方法区)
  • 方法返回地址

👉 示例

java 复制代码
public static void main(String[] args) {
    int a = 10;
    int b = 20;
    int c = a + b;
}

在栈中的表现(简化):

text 复制代码
slot[0] = 10  // a
slot[1] = 20  // b
slot[2] = 30  // c

三、堆(Heap)是什么?

👉 本质

堆是线程共享的,用来存储对象实例


👉 特点

  • 所有线程都可以访问
  • JVM 中最大的一块内存
  • 垃圾回收(GC)主要发生在这里

👉 示例

java 复制代码
Person p = new Person();

内存结构:

text 复制代码
栈:
p → 0x0012(地址)

堆:
0x0012 → Person对象

四、核心区别(对比表)

对比维度 栈(Stack) 堆(Heap)
存储内容 方法运行数据 对象实例
线程 私有 共享
生命周期 方法结束即释放 由 GC 回收
访问速度 相对较慢
空间大小
是否支持 GC
异常 StackOverflowError OutOfMemoryError

五、执行流程对比(重点)

来看一段代码:

java 复制代码
public static void main(String[] args) {
    Person p = new Person();
}

执行过程:

1️⃣ main 方法入栈

text 复制代码
栈:
main 栈帧

2️⃣ 执行 new Person()

text 复制代码
堆:
创建 Person 对象

栈:
p = 对象地址

3️⃣ 建立关系

text 复制代码
栈(引用) → 指向 → 堆(对象)

六、一个常见误区

❌ 错误理解:

栈里存变量名,堆里存对象

✅ 正确理解:

text 复制代码
栈里:
存的是变量的值 或 引用(地址)

堆里:
存的是对象本身

七、为什么要这样设计?

👉 栈的设计目的

  • 快速执行方法
  • 自动释放(无需 GC)
  • 支持函数调用结构(递归等)

👉 堆的设计目的

  • 存储复杂对象
  • 支持对象共享
  • 统一由 GC 管理生命周期

八、面试高频问题总结

✔ 对象一定在堆吗?

👉 一般情况下是(逃逸分析优化除外)


✔ 引用在哪里?

👉 栈(局部变量表)


✔ 为什么栈快?

👉 连续内存 + 简单分配(入栈/出栈)


✔ 为什么堆慢?

👉 需要 GC 管理 + 内存不连续


✔ 什么情况下栈会溢出?

👉 递归过深 → StackOverflowError


✔ 什么情况下堆会溢出?

👉 对象过多 → OutOfMemoryError


九、终极总结

text 复制代码
栈:方法怎么执行
堆:数据存在哪里

再补一句更完整的:

text 复制代码
栈存引用,堆存对象

十、结语

理解栈和堆,是掌握 JVM 的第一步:

  • 看懂 GC → 必须懂堆
  • 看懂方法执行 → 必须懂栈
  • 写高性能代码 → 两者都要理解

如果你能把本文内容吃透,JVM 基础已经非常扎实了。