JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 本文详细介绍了JVM中的GC算法,包括年轻代的复制算法和老年代的标记-整理算法。复制算法适用于年轻代,因其高效且能避免内存碎片;标记-整理算法则用于老年代,虽然效率较低,但能有效解决内存碎片问题。文章还解释了这两种算法的具体过程及其优缺点,并简要提及了其他GC算法。

大厂面试真题:GC 算法有多少种?各自优缺点是什么?年轻代和年老代选择哪种算法最优?

     首先回顾一个图,也就是.class文件的类加载过程,以及线程执行、java内存模型图。看过系列1、2、3三篇文章的同学,大脑先回顾一遍类加器类型、双亲委派机制、如何打破双亲委派机制、GC内存划分、各个区域存放什么数据、以及给你一段代码要知道具体如何执行,对象什么时候被回收的逻辑。有道是,磨刀不误砍柴工,温故而知新,巩固基础,修炼JVM调优进阶核心技术。


       然后堆内存空间区域划分,在上一篇文章系列2以及说过,具体如下图,再回顾一下,年轻代分了Eden区和S1、S2区,堆内存里除了年轻代,其他都是老年代空间。

     今天重点讲的就是堆内存的GC算法以及GC处理过程,一步步来,希望本系列(预计100篇)结题的时候,有缘刷到的同学都有所收获,都能做JVM线上问题排查和JVM调优。


一、年轻代GC 复制算法

      我们知道,当一个新对象要存到堆内存里,这里暂且不说大对象,对象都是优先放到年轻代的Eden区。那随着时间推移,如下图Eden区满了,怎么办?答案:那肯定是要发生YGC,也就是Minor GC。

YGC采用的是什么GC算法?

答: 复制算法。

那为什么选这个算法?

答:稍等,后文解答。

复制算法核心逻辑是:将GC发现有GC Roots也就是还存活的对象,统一挪到S区。


1.1 复制算法的三个阶段

1、标记阶段

从GC Roots集合开始,标记还存活被引用的对象;

2、转移阶段

即把存活对象复制到新的内存地址上。

3、重定位阶段

因为复制转移导致对象的地址发生了变化,在这个重定位阶段,要把所有指向对象的旧地址的指针调整为新内存地址。

1.2 举例具体YGC过程

1、最开始,所有新对象在Eden区,发生YGC后,将存活的对象放到S1区;

2、再发生YGC,就把Eden区和S1区的存活对象,放到S2区。新对象继续放Eden区;

3、再发生YGC,就把Eden区和S2的存活对象,放到S1区。新对象继续放Eden区;

2和3反复。

如下图,当YGC结束后,Eden区就变干净,S区的1或2会存放存活对象,而另一个S区也是干净的。


1.3 复制算法有什么优点?

实现简单,另外由于没有标记和清除过程,执行效率高(毕竟存活的对象总是很少),而且复制对象到S区,使得内存空间总是连续的,没有空间碎片,那内存碎片问题就解决了。另外通过Eden+S1+S2三个区,而且是8:1:1的空间比例,内存利用率也很高,高达90%,仅仅浪费10%,相比传统复制算法只分两个区(5:5占比划分),内存利用率大幅提升。

1.4 复制算法的缺点是什么?

唯一缺点,就是没有100%利用内存,会有一些浪费。目前年轻代的这种分区复制算法,以及非常优秀,仅浪费10%左右内存,这个参数可以根据实际情况进行JVM调优。

看完复制算法的优缺点,这回就知道年轻代为什么适合用复制算法了:核心是年轻代每次GC后存活的对象很少,用复制算法效率高。

1.4 年轻代对应的垃圾回收器有哪些?

年轻代对应的GC回收器有Serial 垃圾回收器、ParNew垃圾回收器。


二、老年代GC 标记-整理算法

    老年代的GC,也就是FullGC,那FullGC什么时候会触发呢?

    一般就是当YGC之后发现存活对象很多,S区放不下了,或者触发某些规则,必须放老年代那边。这时候会去检查老年代还有多少空闲空间,如果发现老年代那边的空闲空间放不下,那就要先发生一个FullGC腾空间。

     老年代FullGC主流采用的是标记-整理算法,核心原理大概是这样:

 把老年代里的存活对象标记处理,然后清理那些已经可以GC回收的对象。最后把相关存活对象归集整理放在一篇连续内存区域,避免有内存碎片。

      老年代的这个标记回收算法,是非常慢的,效率比年轻代回收慢一个数量级。

      老年代对应的GC回收器有Serial Old垃圾回收器、CMS垃圾回收器。

2.1 标记-整理算法过程具体说说

1、标记(Marking)

与其他算法标记类型,从根对象开始,标记出所有存活的对象。

2、整理(Compacting)

在标记清除可以被回收的对象后,将所有存活的对象向一片连续内存移动,这样可以消除内存碎片提高老年代的内存使用率。

3、更新引用

在整理过程中,由于对象位置有挪动修改,所以对象内部的引用也需要进行同步更新,以指向移动后的对象地址。

  发现这个过程和复制算法是差不多的,核心差异在整理那,不过那细讲也要写一篇来说,后续出文再讲。

2.2 标记整理算法的优缺点是什么?

优点:解决了标记-清理算法存在的内存碎片问题,使得内存空间更加紧凑,提高了内存利用率。

缺点:由于需要对存活对象进行移动,这会导致一定的性能开销,降低了GC效率。

2.3 老年代为什么不用复制算法?

     老年代的标记整理算法竟然效率这么低,为啥不该用复制算法呢?

      这是因为老年代的对象存活率会较高,每次FGC,很可能有超过50%对象还会存活。如果存活的对象多,那复制操作的效率也一样会变低。同样,有一个的标记清除算法也可以应用在老年代中,但是它效率和标记整理算法差不多,也不高,且在内存回收后容易产生大量内存碎片。因此标记整理算法(Mark-Compact)算法,是老年代较优的选择。

本文仅重点介绍分区复制算法、还有标记整理算法,除了这两个还有标记-清除算法(Mark-Sweep)、分代收集算法(Generational Collection)。这里不再赘述。


推荐阅读:

1、JVM进阶调优系列(3)堆内存的对象什么时候被回收?

2、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

3、JVM进阶调优系列(1)类加载器原理一文讲透

4、JAVA并发编程系列(13)Future、FutureTask异步小王子

目录
打赏
0
0
0
0
106
分享
相关文章
JVM实战—8.如何分析jstat统计来定位GC
本文详细介绍了使用jstat、jmap和jhat等工具分析JVM运行状况的方法,以及如何合理优化JVM性能。内容涵盖新生代与老年代对象增长速率、Young GC和Full GC的触发频率及耗时等关键指标的分析。通过模拟BI系统和计算系统的案例,展示了如何根据实际场景调整JVM参数以减少FGC频率,提升系统性能。最后汇总了常见问题及其解决方案,帮助开发者更好地理解和优化JVM运行状态。
JVM实战—8.如何分析jstat统计来定位GC
JVM实战—7.如何模拟GC场景并阅读GC日志
本文主要介绍了:如何动手模拟出频繁Young GC的场景、JVM的Young GC日志应该怎么看、编写代码模拟动态年龄判定规则进入老年代、编写代码模拟S区放不下部分进入老年代、JVM的Full GC日志应该怎么看。
JVM实战—7.如何模拟GC场景并阅读GC日志
JVM实战—4.JVM垃圾回收器的原理和调优
本文详细探讨了JVM垃圾回收机制,包括新生代ParNew和老年代CMS垃圾回收器的工作原理与优化方法。内容涵盖ParNew的多线程特性、默认线程数设置及适用场景,CMS的四个阶段(初始标记、并发标记、重新标记、并发清理)及其性能分析,以及如何通过合理分配内存区域、调整参数(如-XX:SurvivorRatio、-XX:MaxTenuringThreshold等)来优化垃圾回收。此外,还结合电商大促案例,分析了系统高峰期的内存使用模型,并总结了YGC和FGC的触发条件与优化策略。最后,针对常见问题进行了汇总解答,强调了基于系统运行模型进行JVM参数调优的重要性。
JVM实战—4.JVM垃圾回收器的原理和调优
JVM实战—5.G1垃圾回收器的原理和调优
本文详细解析了G1垃圾回收器的工作原理及其优化方法。首先介绍了G1通过将堆内存划分为多个Region实现分代回收,有效减少停顿时间,并可通过参数设置控制GC停顿时长。接着分析了G1相较于传统GC的优势,如停顿时间可控、大对象不进入老年代等。还探讨了如何合理设置G1参数以优化性能,包括调整新生代与老年代比例、控制GC频率及避免Full GC。最后结合实际案例说明了G1在大内存场景和对延迟敏感业务中的应用价值,同时解答了关于内存碎片、Region划分对性能影响等问题。
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
Java虚拟机调优指南####
本文深入探讨了Java虚拟机(JVM)调优的精髓,从内存管理、垃圾回收到性能监控等多个维度出发,为开发者提供了一系列实用的调优策略。通过优化配置与参数调整,旨在帮助读者提升Java应用的运行效率和稳定性,确保其在高并发、大数据量场景下依然能够保持高效运作。 ####
68 1
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
JVM简介—1.Java内存区域
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
665 166
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等