JVM 虚拟机栈(Stack)与堆(Heap)深度解析

一、整体认识

在 JVM 内存结构中:

  • 栈(Stack):线程私有,管理方法调用

  • 堆(Heap):线程共享,存储对象

👉 一句话总结:

栈管运行,堆管存储


二、虚拟机栈(Stack)详解

1. 什么是虚拟机栈

虚拟机栈是每个线程独有的内存区域,随着线程创建而创建,线程结束而销毁。


2. 栈的核心结构:栈帧

每次方法调用,都会创建一个栈帧(Stack Frame)

栈帧包含:

  1. 局部变量表

  2. 操作数栈

  3. 动态链接

  4. 方法返回地址


3. 栈的执行流程

java 复制代码
public void methodA() {
    methodB();
}

执行过程:

  1. methodA 入栈

  2. 调用 methodB → methodB 入栈

  3. methodB 执行完 → 出栈

  4. methodA 继续执行

👉 特点:

先进后出(FILO)


4. 局部变量表

存储:

  • 基本类型(int、double 等)

  • 对象引用(不是对象本身)

👉 示例:

java 复制代码
int a = 10;
User user = new User();
  • a 存在栈中

  • user 是引用(地址)在栈中

  • 对象在堆中


5. 常见异常

1. 栈溢出
bash 复制代码
java.lang.StackOverflowError

原因:

  • 方法递归太深

  • 栈帧过多


2. 栈内存不足(少见)
bash 复制代码
OutOfMemoryError: unable to create new native thread

原因:

  • 线程过多

三、堆(Heap)详解

1. 什么是堆

堆是 JVM 中最大的一块内存区域,所有线程共享。

👉 作用:

存储所有对象实例


2. 堆的结构(重点)

堆分为:

(1)新生代(Young Generation)

  • Eden 区

  • Survivor 区(S0、S1)


(2)老年代(Old Generation)

存放:

  • 长期存活对象

  • 大对象


3. 对象创建流程

java 复制代码
User user = new User();

过程:

  1. 在 Eden 分配内存

  2. 初始化对象

  3. 引用指向该对象


4. 对象晋升过程

  1. Eden → Survivor

  2. 多次 GC 后 → 老年代


5. 堆的垃圾回收

堆是 GC 的主要区域:

  1. 新生代:Minor GC(频繁)

  2. 老年代:Major GC / Full GC(较少)


6. 常见异常

1. 堆内存溢出
bash 复制代码
java.lang.OutOfMemoryError: Java heap space

原因:

  • 对象过多

  • 内存泄漏


四、栈 vs 堆 核心区别(面试重点)

对比项 栈(Stack) 堆(Heap)
是否共享 ❌ 线程私有 ✅ 线程共享
存储内容 方法调用、局部变量 对象实例
生命周期 随线程 随 GC
分配速度 相对慢
是否 GC ❌ 不需要 ✅ 需要
是否可能溢出 StackOverflowError OOM

五、经典面试问题

1. 对象到底存在哪?

java 复制代码
User user = new User();

👉 分析:

  • user(引用)→ 栈

  • new User()(对象)→ 堆


2. 方法调用发生在哪?

👉 在栈中(栈帧)


3. 为什么栈不需要 GC?

👉 因为:

  • 生命周期明确(方法结束自动释放)

  • 不存在"垃圾对象"


4. 为什么堆需要 GC?

👉 因为:

  • 对象生命周期不确定

  • 存在无用对象


六、深入理解(加分项)

1. 为什么栈快?

原因:

  1. 内存连续

  2. 由编译器管理

  3. 无需 GC


2. 为什么堆慢?

原因:

  1. 动态分配

  2. 需要 GC

  3. 存在碎片


3. 引用传递本质

Java 中:

👉 传递的是"值",但对象是引用值


七、实际问题分析

场景1:递归导致栈溢出

java 复制代码
public void test(){
    test();
}

👉 无限入栈 → StackOverflowError


场景2:堆内存泄漏

java 复制代码
List list = new ArrayList();
while(true){
    list.add(new Object());
}

👉 对象一直存在 → OOM


八、调优建议(实战)

1. 栈大小设置

bash 复制代码
-Xss1m

👉 每个线程栈大小


2. 堆大小设置

bash 复制代码
-Xms512m
-Xmx1024m

3. 排查工具

  1. jvisualvm

  2. jmap

  3. MAT


九、一句话总结

👉 栈和堆本质区别:

栈负责方法执行,堆负责对象存储


十、终极理解(面试加分)

👉 可以这样总结:

  • 栈解决的是"程序如何运行"

  • 堆解决的是"数据存在哪里"

  • GC 解决的是"数据什么时候清理"

相关推荐
Oueii2 小时前
持续集成/持续部署(CI/CD) for Python
jvm·数据库·python
我真会写代码3 小时前
深入理解Java JVM:架构、核心机制与实战调优指南
java·jvm·架构
yunyun321233 小时前
用Python监控系统日志并发送警报
jvm·数据库·python
寻见9034 小时前
Java为什么能“一次编写,到处运行”?JVM到底解决了什么核心痛点?
java·jvm·java ee
小涛不学习4 小时前
JVM 深度解析(面试 + 实战版)
jvm·面试·职场和发展
小涛不学习4 小时前
JVM 面试核心知识全解析(从原理到实战)
jvm·面试·职场和发展
dapeng28704 小时前
使用PyTorch构建你的第一个神经网络
jvm·数据库·python
空空kkk4 小时前
JVM面试知识点总结
java·jvm·面试
dgfhf4 小时前
使用Python处理计算机图形学(PIL/Pillow)
jvm·数据库·python