JVM 核心总结

发布时间:2026/10/14 2:59:08
JVM 核心总结 一、JVM 是什么Java Virtual MachineJava 虚拟机运行 Java 字节码.class文件实现一次编译到处运行的跨平台特性。Java 源码 (.java) → javac 编译 → 字节码 (.class) → JVM 解析执行 → 操作系统机器码三者关系概念组成JDKJRE 开发工具javac、jar、javadoc 等JREJVM Java 基础类库rt.jar 等JVM类加载器 运行时数据区 执行引擎二、JVM 内存区域运行时数据区整体分为线程私有和线程共享两大部分。┌─────────────────────────────────────────────────────┐ │ JVM 运行时数据区 │ ├────────────────────┬────────────────────────────────┤ │ 线程私有每线程一份 │ 线程共享全局 │ ├────────────────────┼────────────────────────────────┤ │ 1. 程序计数器 (PC) │ 1. 堆 (Heap) —— GC 主战场 │ │ 2. Java 虚拟机栈 │ 2. 元空间 (Metaspace) JDK8 │ │ 3. 本地方法栈 │ (JDK7-: 永久代 PermGen) │ │ │ 3. 字符串常量池 (JDK7 在堆中) │ └────────────────────┴────────────────────────────────┘2.1 程序计数器PC Register作用记录当前线程正在执行的字节码指令地址行号。特点唯一不会抛出 OOM 的区域线程私有生命周期与线程相同。2.2 Java 虚拟机栈JVM Stack存储单元栈帧Stack Frame每个方法调用对应一个栈帧的压栈/出栈。栈帧组成组成部分说明局部变量表存储方法参数和局部变量基本类型存值对象存引用操作数栈字节码指令执行时的操作数入栈/出栈动态链接指向运行时常量池中该方法的引用方法返回地址方法退出后返回到调用者的位置异常StackOverflowError线程请求栈深度 虚拟机允许深度如递归太深OutOfMemoryError栈动态扩展时无法申请足够内存2.3 本地方法栈Native Method Stack与虚拟机栈功能类似专门服务native 方法C/C 编写。HotSpot 将本地方法栈和虚拟机栈合二为一。2.4 堆Heap—— 最重要所有对象实例和数组都在堆上分配是GC 的主要管理区域。堆的分代结构JDK8 经典分代模型┌──────────────────────────────────────────┐ │ Heap │ ├────────────────────┬─────────────────────┤ │ 新生代 Young │ 老年代 Old │ │ ┌────┬─────┬────┐ │ │ │ │Eden│ S0 │ S1 │ │ 大对象 / 长期存活 │ │ │ 8 │ 1 │ 1 │ │ │ │ └────┴─────┴────┘ │ │ ├────────────────────┴─────────────────────┤ │ 比例: Eden : S0 : S1 8 : 1 : 1 │ └──────────────────────────────────────────┘JDK8 变化移除永久代PermGen元空间移至本地内存。2.5 元空间Metaspace, JDK8对比项JDK7 及以前永久代JDK8元空间存储位置堆内存JVM 管理本地内存操作系统管理存储内容类信息、常量、静态变量类信息、常量、静态变量、即时编译代码大小限制-XX:MaxPermSize-XX:MaxMetaspaceSize默认无上限OOM 原因类/常量太多类加载过多注意字符串常量池在 JDK7 移到堆中JDK8 依然在堆中。三、对象创建与内存布局3.1 对象内存布局┌──────────────┬──────────────┬──────────────┐ │ 对象头 │ 实例数据 │ 对齐填充 │ │ Object Header│ Instance Data│ Padding │ └──────────────┴──────────────┴──────────────┘对象头包含组成部分内容Mark Word哈希码HashCode、GC 分代年龄、锁状态标志、偏向锁线程 ID 等类型指针指向元空间中类的 Class 对象数组长度仅数组对象有此字段对齐填充保证对象大小是8 字节的整数倍。3.2 对象访问方式方式原理特点句柄访问栈 → 句柄池 → 实例数据指针 类型数据指针对象移动时只改句柄稳定直接指针HotSpot栈 → 实例数据 类型指针速度快HotSpot 默认使用四、垃圾回收GC4.1 判断对象死亡引用计数法对象被引用 1引用失效 -1计数为 0 则回收。缺点无法解决循环引用问题A ↔ B 互相引用计数永远不会为 0。HotSpot不使用此方法。可达性分析HotSpot 使用以GC Roots为起点沿引用链向下搜索不可达的对象判定为垃圾。GC Roots 包括虚拟机栈局部变量表中引用的对象方法区中静态变量引用的对象方法区中常量引用的对象本地方法栈中 JNINative 方法引用的对象被同步锁synchronized持有的对象四大引用类型引用类型回收时机用途强引用Object o new Object()永不回收除非不再被引用普通对象软引用SoftReference内存不足时回收缓存如图片缓存弱引用WeakReference下次 GC 一定回收WeakHashMap、ThreadLocal虚引用PhantomReference任何时候仅做通知对象回收跟踪、NIO 直接内存管理4.2 分代收集思想分代特点回收频率GC 类型新生代Young对象存活短大批快速死亡高频Minor GC老年代Old存活久的大对象低频Major GC对象分配与晋升流程1. 新对象 → Eden 区分配 2. Eden 满 → Minor GC存活对象 → Survivor 区S0 / S1轮换使用 3. 每熬过一次 Minor GC年龄 1 4. 年龄达到 15默认→ 晋升老年代 5. 大对象 → 直接进入老年代-XX:PretenureSizeThresholdGC 类型对比GC 类型回收区域特点Minor GC仅新生代频繁、速度快Major GC仅老年代通常伴随 Minor GCFull GC整个堆 元空间STW 时间长应尽量避免4.3 垃圾收集算法算法过程优点缺点适用区域标记-清除标记垃圾对象 → 直接清除简单产生内存碎片老年代CMS 基础复制算法存活对象复制到新区域 → 清空旧区域无碎片、高效浪费一半内存新生代标记-整理标记存活 → 向一端移动 → 清理边界外无碎片移动成本高、STW 长老年代4.4 常见垃圾收集器⭐ 面试重点经典收集器一览新生代 老年代 ┌─────────────┐ ┌─────────────┐ │ Serial │ ──────→ │ Serial Old │ 单线程Client 模式 │ ParNew │ ──────→ │ CMS │ ParNew CMS 经典组合 │ Parallel │ ──────→ │ Parallel Old│ JDK8 默认吞吐量优先 │ Scavenge │ │ │ └─────────────┘ └─────────────┘ 不分代 ┌─────────────────────────────────────┐ │ G1 (JDK9 默认) — 分区 Region │ │ ZGC (JDK11) — 亚毫秒级停顿 │ │ Shenandoah (JDK12) — 并发回收 │ └─────────────────────────────────────┘收集器详细对比收集器代线程算法目标适用场景Serial新生代单线程复制简单高效Client 模式、单核ParNew新生代多线程复制缩短 STW配合 CMSParallel Scavenge新生代多线程复制吞吐量优先后台计算任务Serial Old老年代单线程标记-整理—Client 模式Parallel Old老年代多线程标记-整理吞吐量配合 Parallel ScavengeCMS老年代并发标记-清除低停顿互联网 Web 应用G1全堆并发标记-整理 复制可预测停顿JDK9 默认大堆ZGC全堆并发染色指针亚毫秒停顿超大堆、低延迟CMS 详细过程4 个阶段1. 初始标记 (STW) — 标记 GC Roots 直接关联对象极短 2. 并发标记 — 从 GC Roots 遍历对象图与用户线程并发耗时长 3. 重新标记 (STW) — 修正并发标记期间变动的对象比初始标记长但可控 4. 并发清除 — 清除垃圾对象与用户线程并发CMS 缺点内存碎片标记-清除算法可能触发 Full GC并发阶段占用 CPU 资源浮动垃圾并发标记期间新产生的垃圾本次 GC 无法回收Concurrent Mode Failure老年代在并发阶段被填满退化到 Serial OldG1 核心特点分区思想将堆分成多个大小相等的Region不再物理划分新生代/老年代。Garbage-First优先回收垃圾最多的 Region最大化收益。可预测停顿可设置期望停顿时间-XX:MaxGCPauseMillis。RSetRemembered Set记录跨 Region 引用避免全堆扫描。各 JDK 版本默认收集器JDK 版本默认收集器JDK 8Parallel Scavenge新生代 Parallel Old老年代JDK 9G1JDK 11G1ZGC 作为实验性功能JDK 17推荐 ZGC低延迟场景五、类加载机制5.1 类加载的 5 个阶段加载 → 验证 → 准备 → 解析 → 初始化 │ │ │ │ │ │ │ │ │ └── 执行静态代码块、静态变量赋代码值 │ │ │ └── 符号引用 → 直接引用内存地址 │ │ └── 静态变量分配内存并赋默认值非代码赋值 │ └── 校验字节码格式、元数据、字节码、符号引用合法性 └── 读取 class 字节码生成 Class 对象放入元空间各阶段详解阶段做什么关键点加载通过全限定名获取字节流 → 转为方法区数据结构 → 生成Class对象可自定义类加载器实现验证文件格式、元数据、字节码、符号引用验证保证 JVM 安全准备为静态变量分配内存设置类型默认值static int a 100;此阶段a 0解析符号引用字面量转为直接引用内存地址可在初始化之后动态绑定初始化执行clinit()方法静态赋值、静态代码块a才变成1005.2 双亲委派模型核心思想类加载器收到加载请求 → 先委派给父加载器 → 父加载器无法加载 → 自己才加载。┌──────────────────────────┐ │ Bootstrap ClassLoader │ ← C 实现加载 rt.jarString/Object 等核心类 │ 启动类加载器 │ $JAVA_HOME/jre/lib/ ├──────────────────────────┤ │ Extension ClassLoader │ ← 加载 ext 目录下的扩展类 │ 扩展类加载器 (JDK9 废弃) │ $JAVA_HOME/jre/lib/ext/ ├──────────────────────────┤ │ Application ClassLoader │ ← 加载 classpath 下用户写的类 │ 应用程序类加载器 │ ├──────────────────────────┤ │ 自定义类加载器 │ ← 继承 ClassLoader实现特殊加载逻辑 └──────────────────────────┘为什么用双亲委派避免类的重复加载父加载器加载过的子加载器不用重复加载保护核心类库安全防止用户自定义java.lang.String替换核心类破坏双亲委派的场景JDBCSPI 机制核心类调用实现类使用线程上下文类加载器Tomcat多个 Web 应用需要隔离各自的类OSGi模块化热部署六、常见 JVM 调优参数速查参数含义示例-Xms初始堆大小-Xms512m-Xmx最大堆大小-Xmx4g-Xmn新生代大小-Xmn256m-Xss线程栈大小-Xss1m-XX:NewRatio老年代/新生代比例-XX:NewRatio2老年代:新生代2:1-XX:SurvivorRatioEden/Survivor 比例-XX:SurvivorRatio8Eden:S08:1-XX:MaxTenuringThreshold晋升老年代年龄阈值-XX:MaxTenuringThreshold15-XX:MetaspaceSize元空间初始大小-XX:MetaspaceSize128m-XX:MaxMetaspaceSize元空间最大大小-XX:MaxMetaspaceSize256m-XX:UseG1GC使用 G1 收集器—-XX:UseZGC使用 ZGC 收集器—-XX:MaxGCPauseMillis期望 GC 停顿时间-XX:MaxGCPauseMillis200七、面试高频问题速答Q1堆和栈的区别维度堆栈存储内容对象实例、数组局部变量、方法调用线程共享全局共享线程私有内存管理GC 自动回收方法结束自动出栈异常OOMStackOverflowError / OOM大小可调-Xmx较小-Xss默认 1MQ2Minor GC、Major GC、Full GC 区别Minor GC仅新生代回收频繁、速度快。Major GC仅老年代回收CMS 的并发收集算 Major GC。Full GC整堆 元空间回收STW 长尽量避免。常见触发条件System.gc()、老年代空间不足、元空间不足、CMS 并发失败等。Q3什么时候对象进入老年代年龄超过MaxTenuringThreshold默认 15大对象直接分配在老年代动态年龄判断Survivor 中同年龄对象大小总和超过 Survivor 一半该年龄及以上直接晋升空间分配担保Minor GC 后 Survivor 放不下直接进入老年代Q4CMS 和 G1 的区别维度CMSG1内存布局连续物理分代分区 Region逻辑分代算法标记-清除标记-整理 复制碎片会产生碎片整理避免碎片停顿预测无法预测可设置停顿目标适用堆大小中小堆 4G-6G大堆 4G-6G并发阶段不压缩可能 Full GC优先回收收益高的 RegionQ5什么是 STWStop The WorldGC 执行时所有用户线程暂停。不同收集器的 STW 时长不同Serial全程 STWCMS仅初始标记和重新标记两个短阶段 STWG1标记阶段和部分回收阶段ZGC亚毫秒级几乎无 STWQ6类加载过程双亲委派为什么这样设计避免重复加载父 ClassLoader 加载过的类子 ClassLoader 不再加载。安全隔离防止自定义的java.lang.String等类篡改核心 API。加载顺序Bootstrap → Extension → Application → 自定义。Q7OOM 常见原因和排查思路类型原因排查Java heap space堆内存不足对象太多jmap -dump MAT/JProfiler 分析GC overhead limit exceededGC 时间 98% 但回收 2%调大堆或优化代码Metaspace类加载过多动态代理、大量 JSP-XX:MaxMetaspaceSize调大unable to create new native thread线程创建过多ulimit -u减少线程或调小-Xss排查工具jps、jstat、jmap、jstack、jconsole、VisualVM、Arthas阿里开源。记忆口诀类加内存 GC堆分两代四区可达分析定生死CMS 低停 G1 分区JDK8 默认 ParallelJDK9 起用 G1。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询