JVM执行过程

JVM平台结构

java语言一次编写,跨平台编译的特征通过JVM实现
翻译字节码工作通过JVM执行引擎完成。

image.png

执行过程

加载

java虚拟机中
class文件通过类加载系统,并通过双拼委派机制进行加载
双亲委任模式


image.png

避免重复加载类(由父到子依次递归确定实现)
阻止恶意代码攻击(不允许跨空间访问对方的受限资源)

image.png

将文件中的常量池,字段,指令,方法等数据加载jvm内存的云心时数据区共享区域中

验证

版本号,标识类文件完整性....
class文件是紧凑的二进制文件


image.png

image.png

准备

在方法区为类的静态变量分配内存并设置默认值

解析

将常量池中被指定的对象引用,指向实际的内存地址,直接引用

初始化

执行静态代码块,为静态变量设置初始值


image.png
image.png

静态调用main方法

image.png
image.png

对象过多,内存不足,jvm会通过垃圾回收机制释放内存
如何判断对象是垃圾
使用哪个垃圾回收器
用了哪些回收算法

线程可以通过引用访问该对象


image.png

垃圾回收机制

1、可达性分析算法

寻找目标
从源头开始,依次标记对象的引用关系,形成一条条链条,不在引用链条的对象就是死对象,内存需要回收,统称为GC的根节点集合。

底层,执行停止指令时,是一个阶段性过程,不是立刻停止,会在机器固定的安全点处停止,这个安全点需要寻找,一条汇编指令,效率极高。

image.png

2、标记清除算法

不会移动对象,将对象原地删除,效率很高,但同时产生大量的空间碎片,降低内存分配效率


image.png

3、标记整理算法

标记整理的对象移动到一侧,标记外的对象一次性删除(空间利用高,复杂度高)


image.png

4、半区复制算法

将存活对象移动到备用内存,将就内存中的垃圾一次性删除(需要备用内存,内存利用率低)


image.png

回收策略

分代回收策略

image.png

研究表明,一轮回收大部分对象都会挂掉,只有极少对象存活,并且活的越久越难挂掉
设计者将堆分成两个部分,

新生代 回收频率高(多用 半区复制算法)分( 诞生区,幸存区)两个部分8:1:1比例

老年代 久活 (多用 标记整理算法)内存多给,

特点:
新生代 诞生区,整合到幸存区,持续久后转入老年代
新生代 对象多溢出,或者大超出情况下,都会直接进入老年代
老年代 存放大量对象,甚至给新生代兜底
复杂度高,影响GC效率


image.png

卡页维护


image.png

垃圾回收器

image.png
  1. 新生代收集器(只回收新生代,基于复制算法)
    (1)Serial GC(串行收集器)
    核心特点:单线程回收,回收时会触发 STW(Stop The World,所有业务线程暂停);
    回收算法:复制算法(Eden + Survivor);
    适用场景:
    ✅ 单核 CPU、小内存应用(如桌面程序、嵌入式设备);
    ✅ 测试 / 调试环境(GC 日志简单,易排查问题);
    优缺点:
    ✅ 优点:实现简单、无线程切换开销,单核下效率高;
    ❌ 缺点:STW 时间长,不适合高并发、大内存应用;
    启用参数:-XX:+UseSerialGC(新生代 + 老年代都用 Serial)。
    (2)ParNew GC(并行新生代收集器)
    核心特点:Serial GC 的多线程版本,仅优化新生代回收的并发性;
    回收算法:复制算法;
    适用场景:
    ✅ 多核 CPU 环境下,配合老年代的 CMS GC 使用(CMS 是老年代收集器,只能和 ParNew/Serial 搭配);
    优缺点:
    ✅ 优点:多线程回收,新生代 GC 速度比 Serial 快;
    ❌ 缺点:仍有 STW,且线程切换有额外开销;
    启用参数:-XX:+UseParNewGC(仅新生代用 ParNew,老年代默认用 Serial Old)。
    (3)Parallel Scavenge GC(并行回收收集器)
    核心特点:多线程回收,追求吞吐量(吞吐量 = 业务线程运行时间 /(业务线程时间 + GC 时间));
    回收算法:复制算法;
    核心特性:支持 “自适应调节策略”(JVM 自动调整新生代大小、Survivor 比例等,无需手动调参);
    适用场景:
    ✅ 后台运算型应用(如大数据处理、批量任务),优先保证吞吐量;
    ✅ JDK8 默认的新生代收集器;
    优缺点:
    ✅ 优点:吞吐量高,适合 CPU 密集型任务;
    ❌ 缺点:STW 时间随内存增大而变长,不适合低延迟要求的场景;
    启用参数:-XX:+UseParallelGC(新生代用 Parallel Scavenge,老年代默认用 Parallel Old)。
  2. 老年代收集器(只回收老年代)
    (1)Serial Old GC(串行老年代收集器)
    核心特点:Serial GC 的老年代版本,单线程回收,基于标记 - 整理算法;
    适用场景:
    ✅ 配合 Serial GC 使用(单核、小内存);
    ✅ 作为 CMS GC 的后备方案(CMS 回收失败时,Serial Old 会兜底);
    启用参数:-XX:+UseSerialGC(自动搭配 Serial Old)。
    (2)Parallel Old GC(并行老年代收集器)
    核心特点:Parallel Scavenge 的老年代版本,多线程回收,追求吞吐量;
    回收算法:标记 - 整理算法;
    适用场景:
    ✅ 配合 Parallel Scavenge 使用,组成 “并行收集器组合”(JDK8 默认);
    ✅ 后台运算、高吞吐量要求的场景;
    启用参数:-XX:+UseParallelOldGC(指定老年代用 Parallel Old)。
    (3)CMS GC(并发标记清除收集器)
    核心特点:追求低延迟,尽可能减少 STW 时间,基于标记 - 清除算法;
    回收流程(核心!新手重点理解):
    初始标记(STW):标记 GC Roots 直接引用的老年代对象(快,STW 时间短);
    并发标记:和业务线程并行,遍历老年代对象的引用链(无 STW);
    重新标记(STW):修正并发标记期间因业务线程操作导致的标记遗漏(STW 时间比初始标记长,但远短于 Serial Old);
    并发清除:和业务线程并行,清除未标记的垃圾对象(无 STW);
    适用场景:
    ✅ 高并发、低延迟要求的应用(如 Web 服务、电商核心接口);
    优缺点:
    ✅ 优点:并发回收,STW 时间极短,响应速度快;
    ❌ 缺点:
    ① 标记 - 清除算法会产生内存碎片,长期运行可能导致 Full GC;
    ② 并发阶段占用 CPU 资源,会降低业务线程吞吐量;
    ③ 无法处理 “浮动垃圾”(并发清除阶段产生的新垃圾,需下次 GC 回收);
    启用参数:-XX:+UseConcMarkSweepGC(老年代用 CMS,新生代默认用 ParNew)。
  3. 整堆收集器(回收新生代 + 老年代,打破分代模型)
    (1)G1 GC(Garbage-First)
    核心特点:JDK9 及以后默认收集器,兼顾吞吐量和低延迟,打破分代模型(将堆划分为多个大小相等的 Region);
    回收算法:复制算法 + 标记 - 整理算法(按需切换);
    核心特性:
    ✅ 可预测的 STW 时间(通过-XX:MaxGCPauseMillis指定最大暂停时间,JVM 优先回收垃圾多的 Region);
    ✅ 适合大内存应用(堆内存几十 G 甚至上百 G);
    适用场景:
    ✅ 大内存、低延迟要求的应用(如微服务、分布式系统);
    ✅ 替代 CMS GC(解决 CMS 的内存碎片、CPU 占用问题);
    优缺点:
    ✅ 优点:兼顾吞吐量和延迟,支持大内存,无内存碎片;
    ❌ 缺点:实现复杂,小内存场景下性能不如 Parallel GC;
    启用参数:-XX:+UseG1GC。
    (2)ZGC(Z Garbage Collector)
    核心特点:JDK11 引入的实验性收集器(JDK15 正式发布),超低延迟(STW 时间控制在毫秒级),支持 TB 级堆内存;
    回收算法:基于染色指针 + 复制算法;
    核心特性:
    ✅ STW 时间不随堆内存大小增长而变长(即使堆内存 100G,STW 仍在 1ms 内);
    ✅ 并发回收,几乎不影响业务线程;
    适用场景:
    ✅ 超大内存、极致低延迟要求的场景(如金融交易、实时风控);
    启用参数:-XX:+UseZGC(需 JDK11+,Linux 系统支持最好)。
    (3)Shenandoah GC
    核心特点:和 ZGC 定位类似,追求超低延迟,由 RedHat 开发,JDK12 引入(JDK17 正式发布);
    核心特性:
    ✅ 并发整理内存(解决 G1 的 STW 整理问题);
    ✅ 跨平台支持(Linux/Windows/Mac);
    适用场景:
    ✅ 低延迟、大内存应用,对跨平台有要求的场景;
    启用参数:-XX:+UseShenandoahGC(需 JDK12+)。
  4. 其他特殊收集器
    Epsilon GC:“无操作” 收集器,不回收任何垃圾,仅用于性能测试 / 内存泄漏排查(OOM 时直接崩溃);
    启用参数:-XX:+UseEpsilonGC;
    Shenandoah GC/ZGC:属于 “低延迟收集器”,是 JDK 后续版本的重点优化方向。

新手实操建议

日常开发:无需手动指定收集器,用 JDK 默认即可(JDK8 用 Parallel 组合,JDK9 + 用 G1);
性能调优:
追求吞吐量(后台任务):用 Parallel Scavenge + Parallel Old;
追求低延迟(Web 服务):JDK8 用 ParNew + CMS,JDK9 + 用 G1;
超大内存(几十 G 以上):用 ZGC/Shenandoah GC;
排查问题:先用 Serial GC(日志简单)定位问题,再换对应收集器优化。

总结

核心分类:新生代收集器(Serial/ParNew/Parallel Scavenge)、老年代收集器(Serial Old/Parallel Old/CMS)、整堆收集器(G1/ZGC/Shenandoah);
核心选择原则:吞吐量优先选 Parallel 组合,低延迟优先选 G1/ZGC,小内存选 Serial;
版本趋势:G1 是 JDK 默认的主流收集器,ZGC/Shenandoah 是低延迟场景的未来方向。
简单记:新手先掌握 “Parallel(吞吐量)、G1(兼顾)、CMS(低延迟)” 三个核心收集器,足以应对 80% 的开发和调优场景。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容