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 解决的是"数据什么时候清理"

相关推荐
2401_831419445 分钟前
Python分类汇总怎么做_Crosstab交叉表与多条件联合频数频率统计
jvm·数据库·python
2301_787312437 分钟前
Go语言怎么用channel做信号通知_Go语言channel信号模式教程【完整】
jvm·数据库·python
2301_8180084413 分钟前
如何删除ASM中的数据文件_ALTER DISKGROUP DROP FILE彻底清除
jvm·数据库·python
2401_8987176627 分钟前
mysql如何进行全量数据库备份_mysqldump工具的使用技巧
jvm·数据库·python
wuminyu29 分钟前
专家视角看Lambda表达式的原理解析
java·linux·c语言·jvm·c++
m0_7485548132 分钟前
SQL注入的安全架构设计_将数据库置于内网隔离区
jvm·数据库·python
iAm_Ike1 小时前
怎么关闭MongoDB不需要的HTTP管理接口及REST API
jvm·数据库·python
m0_741173331 小时前
CSS移动端实现卡片悬浮投影_利用box-shadow设置层次感
jvm·数据库·python
sinat_383437361 小时前
如何在 Laravel 中筛选并格式化匹配预定义列表的产品数据
jvm·数据库·python
2401_846339561 小时前
mysql如何用执行流程思维写好SQL_SQL优化方法总结
jvm·数据库·python