前言

很多 Java 初学者学会了基础语法、面向对象,却始终搞不懂我们写的 Java 代码到底是怎么跑起来的,也不明白为什么 Java 能称霸企业级开发,更不知道线上内存溢出、卡顿该怎么解决

这篇文章不讲晦涩理论,全程大白话 + 实战,带你吃透 JVM 核心知识点:Java 代码执行流程、跨平台原理、JDK/JRE/JVM 区别、运行时数据区、垃圾回收、类加载、JVM 调优、可视化工具。

不管是面试、期末复习,还是解决实际生产问题,这一篇就够了!


一、灵魂 4 问:搞懂 JVM 的前提

1. 我们写的 Java 代码,电脑是怎么认识的?

电脑只认识二进制 0/1,完全看不懂我们写的HelloWorld.java

Java 代码执行流程(必须背下来):

  1. 程序员编写 .java 源文件(人能看懂,电脑看不懂)
  2. 使用 javac 编译器 → 编译成 .class 字节码文件(JVM 能看懂)
  3. JVM 类加载器加载字节码
  4. 执行引擎将字节码 → 编译成机器码(电脑最终能看懂并运行)

一句话总结:Java 文件 → 编译成 Class 文件 → JVM 识别 → 翻译成机器指令 → 电脑运行

2. 为什么说 Java 是跨平台语言?一次编写,到处运行?

核心答案:因为有 JVM 虚拟机

  • Windows、Linux、Mac 系统都有对应的 JVM
  • JVM 屏蔽了底层操作系统、硬件的差异
  • 我们只需要生成一份 .class 文件,在任何安装了 JVM 的机器上都能跑

对比 C/C++:C/C++ 是直接编译成对应系统的机器码,换系统必须重新编译,代码还可能不兼容。

3. JDK、JRE、JVM 到底有什么区别?(面试高频)

一句话包含关系:JDK > JRE > JVM

  • JVM:Java 虚拟机,真正运行 Java 代码的地方
  • JRE:Java 运行环境 = JVM + 核心类库(C/C++ 编写)
  • JDK:Java 开发工具包 = JRE + 编译工具 (javac) + 监控工具 + 调试工具

✅ 总结:

  • 运行 Java 程序:装 JRE 就行
  • 开发 Java 程序:必须装 JDK

4. 我们为什么要学习 JVM?

Java 自带自动内存管理、自动垃圾回收,开发时几乎不用管内存,那为什么还要学?

两个最真实的理由:

  1. 线上出问题你得会排查内存溢出 (OOM)、内存泄漏、频繁 GC 导致卡顿、服务崩溃
  2. 项目性能优化必须会 JVM高并发下调优、减少停顿、提升吞吐量

就像人不用管食物怎么消化,但生病了必须去医院


二、JVM 核心:运行时数据区(内存模型)

JVM 运行时,数据都存在哪里?这是 JVM 最重要的知识点。

五大区域划分

  1. 程序计数器(线程私有)
  2. 虚拟机栈(线程私有)
  3. 本地方法栈(线程私有)
  4. 堆内存(线程共享)
  5. 方法区(线程共享)

2.1 程序计数器

  • 作用:记录当前线程执行到哪一行字节码指令
  • 特点:线程私有、不会 OOM、很小
  • 场景:线程切换后能恢复到正确执行位置(CPU 时间片切换)

2.2 Java 虚拟机栈(最常考)

  • 线程私有,生命周期和线程一致
  • 每个方法执行 → 创建一个 栈帧
  • 栈帧内部构成:
    • 局部变量表:存放基本类型、对象引用
    • 操作数栈:计算、操作数据
    • 动态链接:方法调用跳转
    • 方法出口:return / 异常

高频面试题:

  • 方法调用方法:会创建多个栈帧
  • 递归调用:会一直压栈 → 太深会栈溢出 StackOverflowError
  • 栈指向堆:栈里存对象引用地址,真实对象在堆里

2.3 本地方法栈

  • 管理 native 方法(底层 C/C++ 代码)
  • 例如:Thread.start() 底层调用 native 方法

2.4 Java 堆(Heap)—— JVM 最大的一块内存

所有对象、数组都在堆上分配!

特点:

  • 线程共享
  • GC 垃圾收集器主要管理区域(GC 堆)
  • 可动态扩展,不足抛出 OOM 内存溢出

堆内存划分(分代回收):

  • 新生代 (1/3):Eden : From : To = 8:1:1
  • 老年代 (2/3)

2.5 方法区

  • 线程共享
  • 存储:类信息、常量、静态变量、即时编译代码
  • JDK8 以后叫 元空间 (Metaspace)

三、直接内存 & 执行引擎 & 垃圾回收系统

3.1 直接内存(堆外内存)

不属于 JVM 运行时数据区,但 NIO 大量使用。

堆内存 VS 直接内存

  • 分配速度:堆内存 > 直接内存
  • 读写速度:直接内存 >>> 堆内存
  • 使用场景:频繁 IO 读写(网络、文件)

3.2 JVM 执行引擎

.class 字节码 → 翻译成 机器码,让 CPU 执行。

3.3 垃圾收集系统(GC)

Java 最强大的能力:自动回收垃圾,不用手动 free


四、JVM 垃圾回收机制(GC)全网最通俗讲解

4.1 什么是垃圾?

没有任何引用指向的对象,就是垃圾,需要被回收。

4.2 如何判断对象可以回收?

① 引用计数法(JVM 不采用)
  • 每个对象有个计数器
  • 有引用 + 1,引用删除 - 1
  • 为 0 就回收
  • 致命缺点:无法解决循环引用
② 可达性分析算法(JVM 采用)

GC Roots 往下找,找不到引用链 → 判定为垃圾。

可作为 GC Roots 的对象:

  • 虚拟机栈中引用的对象
  • 静态变量引用的对象
  • 常量引用的对象
  • 本地方法栈引用的对象

4.3 垃圾回收算法

1)复制算法
  • 把存活对象复制到空区域
  • 优点:速度快、无碎片
  • 适用:新生代
2)标记 - 清除算法
  • 先标记垃圾,再清除
  • 缺点:效率低、产生内存碎片
  • 适用:老年代
3)标记 - 整理算法
  • 标记后把存活对象挪到一起,清除边界外内存
  • 优点:无内存碎片
  • 适用:老年代
4)分代收集算法(JVM 默认使用)
  • 新生代:对象朝生夕死 → 用复制算法
  • 老年代:对象存活久 → 用标记清除 / 标记整理

4.4 堆内存分代与 GC 类型

  • Minor GC:新生代 GC,频繁、速度快
  • Major GC:老年代 GC,慢
  • Full GC:整堆回收,最慢,尽量避免

对象晋升老年代条件:

  • 年龄默认 15 岁
  • 大对象直接进老年代

五、7 种垃圾收集器(JDK8 必考)

表格

收集器 区域 算法 特点
Serial 新生代 复制 单线程、简单
ParNew 新生代 复制 多线程、配合 CMS
ParallelGC 新生代 复制 吞吐量优先
SerialOld 老年代 标记整理 单线程
ParallelOld 老年代 标记整理 多线程、吞吐量
CMS 老年代 标记清除 低停顿
G1 整堆 混合 JDK9 默认、服务端首选

六、JVM 常用参数配置(生产环境必备)

最核心内存参数

-Xms        初始堆大小
-Xmx        最大堆大小(生产环境建议和Xms一样大)
-Xmn        新生代大小
-Xss        线程栈大小
-XX:NewRatio  新生代:老年代 默认 1:2
-XX:SurvivorRatio Eden:Suvivor 默认8:1:1

GC 收集器设置

-XX:+UseSerialGC        串行
-XX:+UseParNewGC        并行新生代
-XX:+UseParallelGC      吞吐量优先
-XX:+UseConcMarkSweepGC CMS
-XX:+UseG1GC            G1收集器

JVM 参数在哪里配置?

  • IDEA:Run Configuration → VM options
  • Tomcat:catalina.sh/bat 配置 JAVA_OPTS
  • SpringBoot Jar:
java -Xms512m -Xmx512m -jar xxx.jar

七、类加载机制与双亲委派模型

7.1 类加载过程

  1. 加载:读取 class 文件到内存
  2. 验证:检查安全性
  3. 准备:静态变量分配内存
  4. 解析:符号引用转直接引用
  5. 初始化:执行静态代码块、静态变量赋值

7.2 四种类加载器

  1. 启动类加载器(C++):加载核心类 rt.jar
  2. 扩展类加载器:加载 ext 目录
  3. 应用类加载器:加载我们自己写的类
  4. 自定义类加载器

7.3 双亲委派模型(面试必问)

工作原理:子类加载器接到任务 → 交给父类 → 一直传到启动类加载器父类能加载就加载,不能加载才自己加载。

优点:

  1. 避免类重复加载
  2. 沙箱安全:防止核心 API 被篡改(比如自己写 java.lang.Integer)

八、JVM 可视化监控工具

1. VisualVM

JDK 自带,最强免费 JVM 分析工具

  • 监控内存
  • 查看 GC
  • 分析 CPU 占用
  • 排查内存泄漏

位置:JDK/bin/jvisualvm.exe

2. JConsole

简单轻量监控工具。


九、总结(背会这一段应付面试)

  1. Java 代码 → .java → javac → .class → JVM → 机器码
  2. JDK 包含 JRE,JRE 包含 JVM
  3. JVM 内存 = 栈 (线程私有) + 堆 (共享,存对象) + 方法区 + 计数器 + 本地方法栈
  4. GC 使用可达性分析,分代回收:新生代复制算法,老年代标记整理 / 清除
  5. 垃圾收集器:JDK8 默认 Parallel,推荐 G1
  6. 类加载遵循双亲委派,保证安全和不重复加载
  7. JVM 用来排查 OOM、GC 频繁、性能瓶颈
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐