参考:
2025年讲的最好的JVM虚拟机实战教程(JVM内存模型+JVM调优+JVM底层原理+JVM面试题)比啃书效果好多了,一周学完让你少走99%的弯路!_哔哩哔哩_bilibili
一、JDK的体系结构

1.为什么Java可以跨平台

1. 编译阶段:一次编译生成统一字节码
.java源文件通过 javac编译命令,编译生成 ".class字节码文件"字节码是一套不绑定 Windows/Linux/macOS 任何操作系统、独立于硬件平台的中间指令,只面向 JVM 规范,和底层系统无关。
2. 运行阶段:不同系统安装对应版本 JVM
使用java命令运行.class时:
- Windows 系统安装Windows 版 JVM
- Linux 系统安装Linux 版 JVM
JVM 是平台相关的:不同操作系统有各自适配系统内核的 JVM 实现,由厂商针对系统单独开发。
3. JVM 屏蔽底层系统差异(核心)
JVM 本质是一个虚拟计算机,在软件层隔离操作系统、CPU 硬件的底层指令差异:同一份.class字节码,交给对应系统的 JVM 后,JVM 会把统一字节码翻译成当前本机操作系统能识别的机器码执行。
总结一句话
一次编译,到处运行:源文件统一编译成与平台无关的 class 字节码,依靠各操作系统专属的 JVM 做适配翻译,实现跨平台。
关键点:Java 程序 (.class) 跨平台,JVM 本身不跨平台。
二、JVM虚拟机内存模型

1. 程序计数器【线程私有】
- 作用:记录当前线程正在执行的字节码行号,用于线程切换后恢复执行位置、指引字节码引擎顺序执行指令;
- 唯一没有 OOM(内存溢出)的内存区域;
- 执行 native 本地方法时,计数器值为空。
2. 栈(线程)【线程私有】

①、基础特性:线程私有
②、内部结构:栈帧(核心)
虚拟机栈由多个栈帧(Frame)组成,每调用 1 个方法,就往栈顶压入 1 个栈帧;方法执行完毕,栈帧出栈销毁,遵循后进先出栈结构。单个栈帧包含 4 部分:
③、两种异常情况
3. 本地方法栈【线程私有】
- 和虚拟机栈结构功能近似,专门服务于 Native 本地方法(C/C++ 编写的底层方法);
- 负责调用操作系统底层原生方法,同样会抛出栈溢出与 OOM 异常。
4. 堆(Heap)【线程共享,GC 重点区域】

- JVM 中最大的一块内存,所有线程共享;
- 唯一目的:存放所有 Java 对象实例、数组对象,绝大多数对象在这里创建;
- 是垃圾回收(GC)最主要区域,分新生代、老年代;
- 堆内存耗尽无法分配对象 → OutOfMemoryError堆内存溢出。
5. 方法区(JDK8 后→元空间 Metaspace)【线程共享】
JDK1.8 重大改动:方法区从堆中剥离,落地到操作系统本地内存,改名元空间
- 存储内容:已加载类的类信息、常量、静态变量、运行时常量池、编译后的即时代码;
- 元空间使用本地内存,默认无固定上限,内存耗尽同样触发 OOM;
补充:两个外部协作组件(流程图右侧)
三、堆内存细分:老年代与新生代
四、STW 全局暂停机制
五、JVM 调优工具 Arthas 详解
- 监控方法调用耗时、调用次数、异常率;
- 查看类加载信息、JVM 内存实时占用、GC 次数与耗时;
- 反编译线上 Class、动态修改日志级别、排查死锁线程;
- 线上实时定位 OOM、CPU 飙高、线程阻塞等疑难故障。
六、实战:双十一亿级电商网站 JVM 参数调优
七、JVM 高频 10 道面试题详解
01 OOM 一定会导致 JVM 退出吗?

Java 中抛出OutOfMemoryError(OOM)不一定会让整个 JVM 进程退出,最终结果由报错所在线程、代码异常捕获处理逻辑决定,运行表现随程序实现、报错场景、异常策略变化。
分场景详细分析:
主线程出现未捕获 OOM:主线程抛出 OOM 且无 try-catch 捕获时,JVM 一般直接终止退出。原因:主线程是程序核心非守护线程,主线程消亡后若无其余存活非守护线程支撑,JVM 进程结束。
子线程出现未捕获 OOM:非主线程抛出未捕获 OOM 时,仅当前报错子线程终止;只要还有其他非守护线程正常运行,整个 JVM 进程不会退出。
代码捕获并处理 OOM:若通过try-catch捕获OutOfMemoryError并做兜底处理,JVM 可以正常继续运行剩余业务逻辑;常规处理手段有释放闲置内存资源、告警提示、降级业务等。
02 对象一定分配在堆中吗?
不是。JIT 逃逸分析开启后,方法内未逃逸的局部小对象会栈上分配,直接存放在虚拟机栈栈帧,方法结束随栈帧销毁,不经过 GC;超大对象、全局逃逸对象依旧分配堆。
03 内存泄漏和内存溢出的区别
04 JVM 对象分配内存如何保证线程安全
两种方案:
05 堆一定是线程共享的吗?
整体堆空间属于线程共享,但 TLAB(线程本地分配缓冲区)是堆划分给单线程独占的小块内存,线程之间 TLAB 隔离,仅共享堆主空间。
06 Class 常量池和运行时常量池的区别
07 运行时常量池和字符串常量池的区别
08 什么情况会导致 JVM 退出
09 JVM 内存为什么要分代
10 GC 是任意时候都能进行的吗
不可以。GC 触发有严格时机限制:
八、Java 完整学习路线图(配套拓展)
结尾总结
JVM 是 Java 后端面试核心重难点,吃透运行时内存分区、GC 分代、STW、调优工具与实战场景,能应对 80% 企业 JVM 面试提问;日常开发中掌握 Arthas 诊断、GC 日志分析、参数调优,可独立负责线上高并发服务稳定性保障。

