前言很多 Java 初学者学会了基础语法、面向对象却始终搞不懂我们写的 Java 代码到底是怎么跑起来的也不明白为什么 Java 能称霸企业级开发更不知道线上内存溢出、卡顿该怎么解决。这篇文章不讲晦涩理论全程大白话 实战带你吃透 JVM 核心知识点Java 代码执行流程、跨平台原理、JDK/JRE/JVM 区别、运行时数据区、垃圾回收、类加载、JVM 调优、可视化工具。不管是面试、期末复习还是解决实际生产问题这一篇就够了一、灵魂 4 问搞懂 JVM 的前提1. 我们写的 Java 代码电脑是怎么认识的电脑只认识二进制 0/1完全看不懂我们写的HelloWorld.java。Java 代码执行流程必须背下来程序员编写.java源文件人能看懂电脑看不懂使用javac编译器 → 编译成.class 字节码文件JVM 能看懂JVM 类加载器加载字节码执行引擎将字节码 → 编译成机器码电脑最终能看懂并运行一句话总结Java 文件 → 编译成 Class 文件 → JVM 识别 → 翻译成机器指令 → 电脑运行2. 为什么说 Java 是跨平台语言一次编写到处运行核心答案因为有 JVM 虚拟机。Windows、Linux、Mac 系统都有对应的 JVMJVM 屏蔽了底层操作系统、硬件的差异我们只需要生成一份.class文件在任何安装了 JVM 的机器上都能跑对比 C/CC/C 是直接编译成对应系统的机器码换系统必须重新编译代码还可能不兼容。3. JDK、JRE、JVM 到底有什么区别面试高频一句话包含关系JDK JRE JVMJVMJava 虚拟机真正运行 Java 代码的地方JREJava 运行环境 JVM 核心类库C/C 编写JDKJava 开发工具包 JRE 编译工具 (javac) 监控工具 调试工具✅ 总结运行 Java 程序装JRE就行开发 Java 程序必须装JDK4. 我们为什么要学习 JVMJava 自带自动内存管理、自动垃圾回收开发时几乎不用管内存那为什么还要学两个最真实的理由线上出问题你得会排查内存溢出 (OOM)、内存泄漏、频繁 GC 导致卡顿、服务崩溃项目性能优化必须会 JVM高并发下调优、减少停顿、提升吞吐量就像人不用管食物怎么消化但生病了必须去医院。二、JVM 核心运行时数据区内存模型JVM 运行时数据都存在哪里这是 JVM 最重要的知识点。五大区域划分程序计数器线程私有虚拟机栈线程私有本地方法栈线程私有堆内存线程共享方法区线程共享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 垃圾收集系统GCJava 最强大的能力自动回收垃圾不用手动 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新生代复制多线程、配合 CMSParallelGC新生代复制吞吐量优先SerialOld老年代标记整理单线程ParallelOld老年代标记整理多线程、吞吐量CMS老年代标记清除低停顿G1整堆混合JDK9 默认、服务端首选六、JVM 常用参数配置生产环境必备最核心内存参数-Xms 初始堆大小 -Xmx 最大堆大小生产环境建议和Xms一样大 -Xmn 新生代大小 -Xss 线程栈大小 -XX:NewRatio 新生代:老年代 默认 1:2 -XX:SurvivorRatio Eden:Suvivor 默认8:1:1GC 收集器设置-XX:UseSerialGC 串行 -XX:UseParNewGC 并行新生代 -XX:UseParallelGC 吞吐量优先 -XX:UseConcMarkSweepGC CMS -XX:UseG1GC G1收集器JVM 参数在哪里配置IDEARun Configuration → VM optionsTomcatcatalina.sh/bat 配置 JAVA_OPTSSpringBoot Jarjava -Xms512m -Xmx512m -jar xxx.jar七、类加载机制与双亲委派模型7.1 类加载过程加载读取 class 文件到内存验证检查安全性准备静态变量分配内存解析符号引用转直接引用初始化执行静态代码块、静态变量赋值7.2 四种类加载器启动类加载器C加载核心类 rt.jar扩展类加载器加载 ext 目录应用类加载器加载我们自己写的类自定义类加载器7.3 双亲委派模型面试必问工作原理子类加载器接到任务 → 交给父类 → 一直传到启动类加载器父类能加载就加载不能加载才自己加载。优点避免类重复加载沙箱安全防止核心 API 被篡改比如自己写 java.lang.Integer八、JVM 可视化监控工具1. VisualVMJDK 自带最强免费 JVM 分析工具监控内存查看 GC分析 CPU 占用排查内存泄漏位置JDK/bin/jvisualvm.exe2. JConsole简单轻量监控工具。九、总结背会这一段应付面试Java 代码 → .java → javac → .class → JVM → 机器码JDK 包含 JREJRE 包含 JVMJVM 内存 栈 (线程私有) 堆 (共享存对象) 方法区 计数器 本地方法栈GC 使用可达性分析分代回收新生代复制算法老年代标记整理 / 清除垃圾收集器JDK8 默认 Parallel推荐 G1类加载遵循双亲委派保证安全和不重复加载JVM 用来排查 OOM、GC 频繁、性能瓶颈