字节、阿里面试都在问的CMS GC问题:9个你一定会遇到的GC问题
yund56 2025-06-17 02:43 5 浏览
"生产环境Full GC频繁,RT超过3秒,该如何优化?" "面试官:讲讲你对CMS GC的理解?" "为什么堆内存还有40%,却频繁发生GC?"
如果你也曾被这些问题困扰,那这篇文章正是为你准备的。
开篇:一个真实的生产事故
凌晨3点,运维紧急电话打来:
"线上订单系统响应超时,监控面板一片飘红..."
登录系统一看,触目惊心:
- GC频率: 2分钟一次Full GC
- RT: P99从200ms飙升到3000ms
- CPU: GC线程占用80%
- 内存: Old区使用率不断攀升
这是一个典型的GC问题,但背后的原因可能有很多:
- 内存泄漏?
- 代码缺陷?
- GC参数配置不当?
- 还是别的什么原因?
让我们通过9个真实案例,深入探究CMS GC的各种问题场景,建立系统的GC问题诊断和优化方法。
为什么要写这篇文章?
在我10年+的Java开发生涯中,遇到最多的就是GC问题。每次面试必问的也是GC。但网上的GC文章要么太浅,要么太深,很少有完整的案例分析。
这篇文章将从实战出发:
- 9个真实案例剖析
- 每个案例都包含问题表现、底层原因、最佳实践
- 配合源码级讲解
- 完整的优化方案
无论你是初学者还是老手,都能从这篇文章中获得成长。
阅读指南
本文较长(预计阅读时间30分钟),建议:
- 先看目录,选择感兴趣的场景
- 准备好JVM工具:jstat、jmap、MAT等
- 动手实践,准备测试程序
- 收藏本文,便于日后查阅
让我们开始这段探索之旅吧!
九种CMS GC问题分析与解决方案详解
一、动态扩容引起的空间震荡
问题表现
- 服务刚启动时GC次数较多
- 最大空间有剩余但仍发生GC
- GC Cause显示"Allocation Failure"
- 每次GC后堆内存空间会被调整
底层原因
// JVM动态扩容的核心代码
void ConcurrentMarkSweepGeneration::compute_new_size() {
// 如果增量收集失败,直接扩容到最大值
if (incremental_collection_failed()) {
grow_to_reserved();
return;
}
// 根据当前使用情况计算新的大小
CardGeneration::compute_new_size();
}
问题在于:
- -Xms和-Xmx设置不一致
- 初始化时只分配-Xms大小空间
- 每次空间不足时要向OS申请内存
- 申请内存过程中必然触发GC
解决方案
- 设置-Xms和-Xmx相等,避免动态扩容
- 合理设置-XX:MinHeapFreeRatio和-XX:MaxHeapFreeRatio
- 预估容量,给JVM足够的初始空间
二、显式GC的去与留
问题表现
- System.gc()导致的Full GC
- 频繁GC但每次回收量不大
- GC日志中出现"System.gc()"
底层原因
public static void gc() {
boolean shouldRunGC;
synchronized(LOCK) {
shouldRunGC = justRanFinalization;
if (shouldRunGC) {
justRanFinalization = false;
} else {
runFinalization();
}
}
if (shouldRunGC) {
runGC();
}
}
显式GC的问题:
- 会触发Full GC,STW时间长
- 打断CMS的并发收集
- 影响系统的吞吐量
解决方案
- 通过-XX:+DisableExplicitGC禁用System.gc()
- 使用-XX:+ExplicitGCInvokesConcurrent将System.gc()转为CMS GC
- 代码优化,避免调用System.gc()
三、MetaSpace区OOM
问题表现
- MetaSpace空间耗尽
- 出现OOM异常
- 伴随着频繁的Full GC
底层原因
// MetaSpace的类加载机制
class ClassLoader {
protected Class<?> loadClass(String name)
throws ClassNotFoundException {
// 1. 查找已加载的类
Class<?> c = findLoadedClass(name);
if (c == null) {
// 2. 尝试加载新类
c = findClass(name);
// 3. 存储到MetaSpace
defineClass(name, b, 0, b.length);
}
return c;
}
}
MetaSpace问题常见原因:
- 动态生成类导致类元数据信息过多
- ClassLoader泄漏
- 反射、动态代理使用不当
解决方案
- 设置合理的MetaSpace大小
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
- 排查类加载和卸载情况
- 检查是否存在ClassLoader泄漏
- 合理使用动态代理等反射机制
四、过早晋升
问题表现
- Young GC频繁
- 对象过早进入老年代
- 老年代空间增长过快
底层原因
// 动态年龄计算
if (age < MaxTenuringThreshold) {
// 计算当前age及以下的对象总大小
size_t total = 0;
for (int i = age; i >= 0; --i) {
total += sizes[i];
if (total > survivor_capacity/2) {
result = i;
break;
}
}
}
过早晋升原因:
- Survivor空间过小
- MaxTenuringThreshold设置过小
- 动态年龄判定导致过早晋升
解决方案
- 调整新生代大小
-XX:NewRatio=4
-XX:SurvivorRatio=8
- 调整对象晋升年龄
-XX:MaxTenuringThreshold=15
- 关注动态年龄计算
- 检查是否存在大对象直接进入老年代
五、CMS Old GC频繁
问题表现
- Old区频繁执行CMS GC
- GC日志中出现大量"CMS Initial Mark"和"CMS Final Remark"
- 每次回收效果不佳
底层原因
// CMS GC触发条件
void CMSCollector::shouldConcurrentCollect() {
// 判断是否需要触发CMS GC
if (_cmsGen->should_concurrent_collect()) {
// 1. 根据空间占用率判断
if (_cmsGen->occupancy() >= _bootstrap_occupancy) {
return true;
}
// 2. 根据增长率判断
if (isGrowingTooFast()) {
return true;
}
}
}
主要原因:
- CMS启动阈值过高
- 空间碎片化严重
- 对象分配速率过快
- 浮动垃圾过多
解决方案
- 调整CMS触发阈值
// 降低触发阈值,提前启动GC
-XX:CMSInitiatingOccupancyFraction=68
-XX:+UseCMSInitiatingOccupancyOnly
- 增大Old区空间
-XX:CMSMaxAbortablePrecleanTime=5000
- 开启空间碎片整理
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
六、单次CMS Old GC耗时长
问题表现
- CMS GC单次停顿时间长
- 出现较长的STW时间
- Final Remark阶段耗时过长
底层原因
// CMS Final Remark阶段的核心代码
void CMSCollector::checkpointRootsFinalWork() {
// 1. 处理Reference
ReferenceProcessor::processReferences();
// 2. 类卸载
if (should_unload_classes()) {
ClassUnloadingWork();
}
// 3. 清理符号表
SymbolTable::clean_up();
}
耗时原因:
- Reference处理慢
- Class卸载耗时长
- Symbol Table清理慢
- 新生代状态不稳定
解决方案
- 优化Reference处理
// 开启并行Reference处理
-XX:+ParallelRefProcEnabled
- 控制Class卸载
// 关闭类卸载
-XX:-CMSClassUnloadingEnabled
- 稳定新生代状态
// Final Remark前强制Young GC
-XX:+CMSScavengeBeforeRemark
七、内存碎片&收集器退化
问题表现
- CMS退化为Serial Old收集器
- 出现"Promotion Failed"或"Concurrent Mode Failure"
- Full GC频繁发生
底层原因
// CMS并发失败处理
void ConcurrentMarkSweepGeneration::collect_in_background() {
if (shouldConcurrentCollect()) {
// 并发收集失败,退化为Serial收集
if (_foregroundGCIsActive) {
collectSerially();
return;
}
// 执行并发收集
collectConcurrently();
}
}
退化原因:
- 空间碎片化严重
- 并发模式失败
- 晋升失败
- 显式GC触发
解决方案
- 控制碎片率
// 配置碎片整理
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=10
- 调整并发参数
// 增加并发线程
-XX:ConcGCThreads=4
// 提前启动CMS
-XX:CMSInitiatingOccupancyFraction=68
- 预留足够空间
// 增大老年代空间
-Xmx4g -Xms4g
八、堆外内存OOM
问题表现
- 进程内存超出堆内存限制
- 出现Direct Memory OOM
- 堆外内存增长快速
底层原因
// DirectByteBuffer分配堆外内存
class DirectByteBuffer {
DirectByteBuffer(int cap) {
// 通过Unsafe分配本地内存
base = unsafe.allocateMemory(size);
// 通过Cleaner管理内存回收
cleaner = Cleaner.create(this, new Deallocator(base, size));
}
}
OOM原因:
- DirectByteBuffer使用不当
- 堆外内存泄漏
- JNI调用未释放
- 本地内存过大
解决方案
- 限制DirectMemory大小
-XX:MaxDirectMemorySize=256M
- 检查DirectByteBuffer使用
- 排查JNI调用
- 开启NMT监控
-XX:NativeMemoryTracking=detail
九、JNI引发的GC问题
问题表现
- GC Locker导致的GC
- Young GC停顿时间变长
- 对象过早晋升
底层原因
// GC Locker机制
class GCLocker {
static void lock() {
// 阻止GC发生
_needs_gc = true;
_jni_lock_count++;
}
static void unlock() {
_jni_lock_count--;
if (_jni_lock_count == 0 && _needs_gc) {
// 触发一次GC
Universe::heap()->collect();
}
}
}
问题原因:
- JNI临界区阻塞GC
- 触发额外的GC
- 导致对象提前晋升
解决方案
- 优化JNI代码
- 减少JNI调用时间
- 避免在JNI中长时间持有锁
- 添加GC参数
// 打印JNI引起的GC信息
-XX:+PrintJNIGCStalls
- 调整堆内存配置
// 增大新生代空间
-XX:NewSize=256m
-XX:MaxNewSize=256m
写在最后
以上九种CMS GC问题是最常见的场景,关键是:
- 建立完善的监控体系
- 保留现场和日志信息
- 掌握问题分析方法
- 积累优化调优经验
记住一句话:
"GC优化不是目的,解决业务问题才是根本。"
#Java性能优化 #GC调优 #JVM
相关推荐
- Excel表格带单位求和不用愁!2个高效小技巧,轻松搞定!
-
我是【桃大喵学习记】,欢迎大家关注哟~,每天为你分享职场办公软件使用技巧干货!——首发于微信号:桃大喵学习记最近有小伙伴私信提问了个问题:“Excel表格数据带单位,如何快速求和?”。相信很多新手小伙...
- [office] Excel中Sumproduct函数的使用方法-
-
Excel中Sumproduct函数的使用方法-SUMPRODUCT和SUMIFS是Excel的两个最强大的函数,用于从表中返回过滤的数据。SUMPRODUCT功能更强大,但SUMIFS更快。您可以...
- SUMPRODUCT函数:关于多条件求和,不仅仅是SUMIFS,我也行!
-
文章最后有彩蛋!好礼相送!SUMPRODUCT函数,作为excel函数公式中的常用功能之一,运用及其广泛。结合它能够处理数据的功能,函数哥将它称之为多条件求和的函数,你可能有疑问了。SUMIF和SUM...
- Excel函数公式大全之利用MMULT函数计算两个数组矩阵的乘积
-
各位Excel天天学的小伙伴们大家好,欢迎收看Excel天天学出品的excel2019函数公式大全课程。今天我们依旧要学习的是Excel函数中的数学函数MMULT函数,计算两个数组的矩阵乘积。今天这个...
- Excel中的这个“万能函数”你用过吗?一个顶四个,简单又实用
-
Hello,大家好,今天跟大家分享一个Excel中的最强大的求和函数,它就是——SUMPRODUCT函数,很多人都将其称之为“万能函数”,条件求和,条件计数等一些常用的功能他就能轻松搞定,逻辑也非常的...
- 根据关键字条件求和,SUMPRODUCT函数思路清晰!
-
1职场实例小伙伴们大家好,今天我们来讲解一个关于根据关键字进行条件求和的职场真实案例,这是公众号粉丝后台留言咨询的一个问题,下面我们来通过几组简单的数据还原一下真实的办公情景。如下图所示:A列为一列地...
- Excel-万能PRODUCT函数
-
sumproduct除了可以计算乘积之和,还可以实现单条件求和(代替sumif),多条件求和(代替sumifs),单条件计数(代替countif),多条件计数(代替countifs)我总结了一个通用的...
- Excel“王者”级求和函数SUMPRODUCT,职场必学!
-
我是【桃大喵学习记】,欢迎大家关注哟~,每天为你分享职场办公软件使用技巧干货!日常工作中我们经常需要对Excel数据求和、计数,今天就跟大家分享一下Excel“王者”级求和函数SUMPRODUCT,灵...
- SUMPRODUCT函数满足“或”的要求,实现多条件求和!
-
1职场实例小伙伴们大家好,今天我们来继续讲解Excel使用中非常实用且强大的函数:SUMPRODUCT函数,上一次我们讲到了SUMPRODUCT函数实现类似SUMIFS函数多条件求和的功能。而今天我们...
- 整列数据相乘再相加sumproduct函数#excel技巧
-
今天分享一下像这种表格,我想求它的消费,也就是用它的数量去乘以单价去加上。下一个的数量乘以单价要加上,下一个数量乘以单价。如果小白会这样一步一步的去算,去单价去乘以数量,然后加上单价去乘以数量,一个一...
- 双向多条件求和,sumifs彻底不行了,但是sumproduct却能轻松搞定
-
今天我们来解决一个困扰很多Excel新手的问题,它就双向求和,所谓的双向,就是两个方向,如下图所示,我们想要根据【项目】与【费用类别】来实现动态求和效果。【项目】与【费用类别】在数据源中,一个是纵横的...
- Excel函数之Sumproduct,7个经典用法,你真的都了解吗?
-
什么是sumproduct函数以及其基本操作原理?sumproduct函数主要用于对数组中的数值进行相乘后再求和,。该函数最多支持255个参数(数组),这些数组可以是数字单元格引用或区域。它的工作流程...
- WPS-Excel表格sumproduct函数一次性算出相乘相加总额
-
excel表格单纯相加或者相乘大家都会应用,但是有时候我们需要算出相乘相加的总额,这种计算也是可以一次性算出的。今天来教大家怎样在WPS表格中,让数据一次性算出相乘相加的总额,会了这个小技巧,会方便很...
- 大神级Sumproduct公式这么好用,1分钟学会!
-
在工作中,一般用不到Sumprodct函数公式,但是真的好用,我们举工作中的3个场景来说明。1、快速相乘相加如下所示,我们各种商品有一个单价,然后对应有一些数量,我们现在需要快速汇总总金额数据有没有小...
- 万能函数Sumproduct,除了求和和计数外,还可以排名
-
在众多的Excel函数中,能同时完成求和、计数以及排名功能的函数不多,其中Sumproduct就是其中一个。一、万能函数Sumproduct:功能及语法结构。功能:返回相应区域数组乘积的和。语法结...
- 一周热门
- 最近发表
-
- Excel表格带单位求和不用愁!2个高效小技巧,轻松搞定!
- [office] Excel中Sumproduct函数的使用方法-
- SUMPRODUCT函数:关于多条件求和,不仅仅是SUMIFS,我也行!
- Excel函数公式大全之利用MMULT函数计算两个数组矩阵的乘积
- Excel中的这个“万能函数”你用过吗?一个顶四个,简单又实用
- 根据关键字条件求和,SUMPRODUCT函数思路清晰!
- Excel-万能PRODUCT函数
- Excel“王者”级求和函数SUMPRODUCT,职场必学!
- SUMPRODUCT函数满足“或”的要求,实现多条件求和!
- 整列数据相乘再相加sumproduct函数#excel技巧
- 标签列表
-
- filter函数js (37)
- filter函数excel用不了 (73)
- 商城开发 (40)
- 影视网站免费源码最新版 (57)
- 影视资源api接口 (46)
- 网站留言板代码大全 (56)
- java版软件下载 (52)
- java教材电子课本下载 (48)
- java技术的电子书去哪看 (33)
- 0基础编程从什么开始学 (50)
- java是用来干嘛的 (51)
- it入门应该学什么 (55)
- java线上课程 (55)
- 学java的软件叫什么软件 (38)
- 程序开发软件有哪些 (53)
- 软件培训 (59)
- 机器人编程代码大全 (50)
- 少儿编程教程免费 (45)
- 新代系统编程教学 (61)
- 共创世界编程网站 (38)
- 亲测源码 (36)
- 三角函数积分公式表 (35)
- 函数的表示方法 (34)
- 表格乘法的公式怎么设置 (34)
- sumif函数的例子 (34)