在Java中,垃圾回收器是自动管理内存的重要工具。垃圾回收器有很多种,其中CMS垃圾回收器和G1垃圾回收器又是其中重要的两种类型,下面我主要讲下这两种垃圾回收器:
CMS垃圾回收器
CMS(Concurrent Mark Sweep)垃圾回收器是Java HotSpot虚拟机中的一个重要组件,是第一款真正意义上的并发回收器,实现了垃圾收集器与用户线程同时工作。以下将深入解析CMS垃圾回收器的工作原理,以及如何通过调整参数来优化其性能。

核心概念:三色标记法
三色标记将堆中对象分为三类,代表不同的扫描进度:
-
黑色:已被 GC 访问过,且其所有引用对象也均已扫描完毕。代表确认存活的对象,GC 不再重新扫描,同时黑色对象不可能直接指向白色对象
-
灰色:已被 GC 访问过,但其引用的子对象尚未全部扫描完毕。它是 GC 线程当前待处理的任务队列。
-
白色:尚未被 GC 访问过的对象。在刚刚分析可达性开始的时候,所有对象会被标记为白色,但是若标记结束后仍为白色,则判定为不可达(垃圾),可被回收。
1、工作流程
1.1、初始标记阶段(initiate Mark Phase)
在初始标记阶段,会通过根节点引用查找方法,把所有有关联的对象都标记出来。这个是STW(stop-the-world ),会暂停应用程序的运行。这时采用的标记方法是三色标记方法
1.2、并发标记阶段(Concurrent Mark Phase)
在这个阶段,在应用程序运行的同时,会对堆内存的对象进行标记出来,这个阶段是并发的,不会影响程序的运行
这个阶段可能会产生两种问题:漏标或多标
漏标:灰色对象断开对白色对象的引用,同时黑色对象新增对该白色对象的引用。由于黑色对象不再扫描,白色对象会被误判为垃圾
CMS解决方案是增量更新:
-
通过写屏障记录黑色对象新增的指向白色对象的引用
-
在重新标记阶段,将这些黑色对象重新置为灰色,并再次扫描其引用,确保白色对象被正确标记为存活
1.3、重新标记阶段(Remark Phase)
在这个阶段,修正并发标记阶段可能错误的标记。这个阶段会触发Stop-The-World事件,但时间较短。
1.4、清理阶段(sweep Phase)
在这个阶段,包括清理和重置线程,期间会释放未被标记的对象所占用的内存,这个阶段也是并发的,不影响程序的运行
2、参数调优
2.1、调整参数 -XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction
使用参数-XX:+UseCMSCompactAtFullCollection可以开启压缩整理阶段,以减少内存碎片和提高内存利用率。使用参数-XX:CMSFullGCsBeforeCompaction可以设置在执行多少次Full GC后执行一次压缩整理。这两个参数可以根据实际情况进行调整。
2.2、调整内存大小 -Xmx和-Xms
调整参数-Xmx和-Xms可以控制Java堆的最大和初始内存大小。如果堆内存过小,可能会导致频繁的Full GC,影响应用的性能。因此,需要根据实际情况调整这两个参数的大小。
2.3、避免大对象直接进入老年代 -XX:+UseLargePages
使用参数-XX:+UseLargePages可以避免大对象直接进入老年代,从而减少Full GC的频率。这个参数适用于有大量大对象的场景。
2.4、分析堆转储(Heap Dump)和垃圾回收日志(GC Log)
分析堆转储和垃圾回收日志可以帮助我们找到内存泄漏和频繁Full GC的原因。通过分析这些日志,我们可以更好地了解应用的内存使用情况,并进行针对性的优化。
3、特点&缺点
3.1 在初始标记和重新标记阶段,CMS会暂停应用程序的运行
3.2 CMS对老年代的清理不够彻底,可能会导致老年代中存在大量的空闲空间
G1
G1(Garbage-First) 是一款面向服务端应用的垃圾收集器,主要针对配备多核CPU及大容量内存的机器,以极高概率满足GC停顿时间的同时,还兼具高吞吐量的性能特征。
重要概念:分区Region
使用G1收集器时,他将整个Java推划分成2048个大小相同的独立Region块,每个Region块大小根据推空间的实际大小而定的,单个Region被控制在1MB到32MB之间,并且是2的N次幂,即1、2、4、8、16、32MB。通过参数-XX:G1HeapRegionSize设定。所有的Region大小相同,且在JVM生命周期内不会改变。
虽然保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,他们都一部分Region(不需要连续)的集合。通过Region的动态分配方
一个Region有可能属于Eden、survivor或者Old区,但是一个Region只可能属于一个角色。图中E代表Eden,S代表Survivor,O代表Old。空白表示未使用区域。
G1还新增加了一种新的内存区域H,叫做Humongous区域,图中H块,主要存储大对象,如果对象超过1.5个region,就放到H

1、工作流程
1.1 初始标记(Initial Marking Phase)
这个过程也是通过根节点引用方式找出所有可达的对象,速度是非常快的,但是也是停止应用程序,有stw(stop-the-world),
1.2 并发标记(Concurrent Mark Phase)
在初始标记完,进入并发标记阶段,这个过程中是不会停止应用程序的,会通过递归的方式进一步把所有的可达对象都标记出来
1.3 最终标记(final Mark Phase)
为了处理在并发标记过程中新产生的对象引用关系,G1 GC会执行一次短暂的STW的最终标记。这个阶段确保所有在并发标记阶段漏掉的对象都被正确标记
1.4 筛选回收(Live Data Counting and Evacuation)
在这个阶段,G1 GC会根据每个Region的垃圾堆积情况和回收价值进行排序,并选择性地回收部分Region中的垃圾对象。回收过程包括将存活的对象从一个Region复制或移动到另一个Region,并更新相关的引用。这个过程也是并发的,旨在最大限度地减少停顿时间。同时,这个阶段可能会涉及到对象的整理和压缩,以减少内存碎片
2、参数调优
2.1、-XX:+UseG1GC:启用G1垃圾收集器
2.2、-XX:G1HeapRegionSize:设置每个region的大小。
2.3、-XX:MaxGCPauseMillis:这个是期望GC最大停顿的时间。
2.4、-XX:InitiatingHeapOccupancyPercent: 这个参数用于设置触发并发GC周期的Java堆占用率阈值,当堆内存达到这个数值,则启动回收机制。
3、特点&缺点
3.1、可预测的停顿时间,高效的内存回收,优化内存分配
3.2、对硬件要求比较高,适合大内存的服务。



实现100%通过率-171主机测评](https://www.171host.com/wp-content/uploads/2026/11/20261105194700-6aecdd3478591-220x80.gif)
