企业是做网站还是做微信,网站是别人做的我这就没有根目录,百度seo搜索,设计网站接单写在前面的话
前几天凌晨2点#xff0c;我被一通电话惊醒——线上交易系统出现了严重的延迟问题#xff0c;用户支付请求响应时间从平时的100ms飙升到了5秒#xff0c;客服电话都被打爆了。
经过紧急排查#xff0c;我们发现罪魁祸首竟然是JVM的垃圾回收器#xff01;当…写在前面的话
前几天凌晨2点我被一通电话惊醒——线上交易系统出现了严重的延迟问题用户支付请求响应时间从平时的100ms飙升到了5秒客服电话都被打爆了。
经过紧急排查我们发现罪魁祸首竟然是JVM的垃圾回收器当时使用的CMS垃圾回收器在高并发场景下出现了严重的停顿导致系统几乎不可用。
这次故障让我深刻认识到选择合适的垃圾回收器不是小事它直接关系到系统的生死存亡。
今天我将把这些年在垃圾回收器选型和调优方面的经验总结出来帮助大家彻底掌握JVM垃圾回收的精髓。
垃圾回收基础为什么需要垃圾回收器
在深入讲解各种垃圾回收器之前我们先来理解一个本质问题为什么Java需要垃圾回收
内存管理的痛点
想象一下如果没有垃圾回收会发生什么
程序员需要手动管理内存像C/C一样一旦忘记释放内存就会导致内存泄漏系统运行时间越长可用内存越少最终导致OOM内存溢出
垃圾回收的工作原理
垃圾回收器的核心任务就是**自动识别和回收不再使用的对象**。这个过程主要分为两个步骤
标记Mark找出哪些对象还在使用哪些已经死亡清除Sweep回收死亡对象占用的内存空间
三色标记算法
为了更好地理解后面的内容我们需要了解三色标记算法
白色未被扫描的对象可能是垃圾灰色已被扫描但其引用的对象还未扫描完成黑色已被扫描且其引用的对象也已扫描完成确定存活
主流垃圾回收器深度解析 1. Serial GC单线程的老前辈
特点
单线程执行垃圾回收回收时必须暂停所有用户线程Stop The World算法简单开销小
适用场景
客户端应用单核心或小内存环境对延迟要求不高的场景
配置参数
-XX:UseSerialGC2. Parallel GC多线程的力量
Parallel GC是JDK 8及之前版本的默认垃圾回收器也是目前应用最广泛的垃圾回收器之一。
核心特点
多线程并行执行垃圾回收注重吞吐量适合后台任务新生代使用Parallel Scavenge老年代使用Parallel Old
关键参数配置
# 启用Parallel GC
-XX:UseParallelGC# 设置垃圾回收线程数一般设置为CPU核心数
-XX:ParallelGCThreads8# 设置期望的吞吐量百分比默认99即GC时间不超过1%
-XX:GCTimeRatio99# 设置最大GC停顿时间目标毫秒
-XX:MaxGCPauseMillis100实战经验 在我们的批处理系统中使用Parallel GC配置如下
-Xms4g -Xmx4g
-XX:UseParallelGC
-XX:ParallelGCThreads8
-XX:GCTimeRatio99效果吞吐量提升15%GC时间占比控制在1%以内。
3. CMS GC并发标记清除的先驱
CMSConcurrent Mark Sweep是第一个真正意义上的低延迟垃圾回收器。
工作流程
初始标记STW标记GC Roots直接关联的对象并发标记与用户线程并发标记所有可达对象重新标记STW修正并发标记期间的变化并发清除与用户线程并发清理垃圾对象 优点
并发收集低停顿适合对响应时间敏感的应用
缺点
产生内存碎片并发阶段会抢占CPU资源容易产生浮动垃圾
关键参数配置
# 启用CMS
-XX:UseConcMarkSweepGC
-XX:UseParNewGC# 设置触发CMS GC的老年代使用率阈值
-XX:CMSInitiatingOccupancyFraction75
-XX:UseCMSInitiatingOccupancyOnly# 并发线程数
-XX:ConcGCThreads4# 开启CMS预清理
-XX:CMSPrecleaningEnabled# 设置预清理阶段的最大持续时间
-XX:CMSMaxAbortablePrecleanTime5000真实案例 某电商系统使用CMS配置
-Xms8g -Xmx8g
-XX:UseConcMarkSweepGC
-XX:UseParNewGC
-XX:CMSInitiatingOccupancyFraction70
-XX:UseCMSInitiatingOccupancyOnly结果平均GC停顿时间从200ms降低到50ms。
4. G1 GC分代收集的革命者
G1Garbage First是JDK 9的默认垃圾回收器代表了垃圾回收技术的重大突破。
核心创新
将堆内存划分为多个大小相等的Region可预测的停顿时间同时回收新生代和老年代
工作流程
初始标记STW标记GC Roots并发标记并发标记整个对象图最终标记STW处理SATB队列筛选回收STW回收价值高的Region 核心数据结构
RSet记忆集记录跨Region引用SATBSnapshot At The Beginning解决并发标记时的漏标问题Card Table细粒度的引用跟踪
关键参数配置
# 启用G1
-XX:UseG1GC# 设置期望的最大停顿时间毫秒
-XX:MaxGCPauseMillis200# 设置Region大小1MB到32MB必须是2的幂
-XX:G1HeapRegionSize16m# 设置并发标记线程数
-XX:ConcGCThreads4# 设置触发Mixed GC的老年代占用率
-XX:G1MixedGCCountTarget8
-XX:G1OldCSetRegionThreshold10# G1相关的调优参数
-XX:G1ReservePercent10
-XX:G1HeapWastePercent5生产实战配置 某金融系统的G1配置
-Xms16g -Xmx16g
-XX:UseG1GC
-XX:MaxGCPauseMillis100
-XX:G1HeapRegionSize16m
-XX:G1MixedGCCountTarget8
-XX:G1PrintRegionRememberedSetInfo效果99.9%的GC停顿时间控制在100ms以内。
5. ZGC超低延迟的未来之星
ZGC是OpenJDK的一个实验性垃圾回收器专注于超低延迟。
革命性特点
停顿时间不超过10ms支持TB级别的堆内存并发回收几乎不需要STW
适用场景
对延迟极度敏感的应用大内存应用实时交易系统
配置参数
# 启用ZGCJDK 11
-XX:UnlockExperimentalVMOptions
-XX:UseZGC# 设置最大堆内存
-Xmx32g# 开启ZGC的分代收集JDK 17
-XX:UseZGC
-XX:ZGenerational6. ShenandoahOpenJDK的低延迟选择
Shenandoah是Red Hat开发的低延迟垃圾回收器。
核心特点
并发回收停顿时间与堆大小无关使用连接矩阵解决并发移动问题
配置参数
# 启用Shenandoah
-XX:UnlockExperimentalVMOptions
-XX:UseShenandoahGC# 设置GC模式
-XX:ShenandoahGCModeiu垃圾回收器横向对比
垃圾回收器停顿时间吞吐量内存开销适用堆大小并发程度Serial GC高高低100MB无并发Parallel GC中最高低8GB并行回收CMS GC低中中2-8GB并发标记G1 GC低中高中高4GB并发并行ZGC极低中高8GB高度并发Shenandoah极低中高8GB高度并发
场景化选择策略
Web应用服务器
场景特点
对响应时间敏感中等并发量堆内存通常在4-16GB
推荐方案
首选G1 GC备选CMS GCJDK 8及以下
配置示例
# G1配置推荐
-Xms8g -Xmx8g
-XX:UseG1GC
-XX:MaxGCPauseMillis100
-XX:G1HeapRegionSize16m# CMS配置兼容性考虑
-Xms8g -Xmx8g
-XX:UseConcMarkSweepGC
-XX:UseParNewGC
-XX:CMSInitiatingOccupancyFraction75批处理系统
场景特点
注重吞吐量对延迟不敏感大量数据处理
推荐方案
首选Parallel GC备选G1 GC大堆场景
配置示例
# Parallel GC配置
-Xms16g -Xmx16g
-XX:UseParallelGC
-XX:ParallelGCThreads16
-XX:GCTimeRatio99实时交易系统
场景特点
极低延迟要求高并发严格的SLA
推荐方案
首选ZGCJDK 11备选Shenandoah
配置示例
# ZGC配置
-Xms32g -Xmx32g
-XX:UseZGC
-XX:UnlockExperimentalVMOptions微服务应用
场景特点
小堆内存快速启动容器化部署
推荐方案
首选G1 GC备选Parallel GC
配置示例
# 微服务G1配置
-Xms1g -Xmx2g
-XX:UseG1GC
-XX:MaxGCPauseMillis50
-XX:G1HeapRegionSize1m性能调优最佳实践
堆内存配置原则
初始堆大小-Xms应该等于最大堆大小-Xmx
-Xms8g -Xmx8g # 避免动态扩容的开销新生代大小要合理
# 一般设置为堆内存的1/4到1/3
-XX:NewRatio3 # 新生代:老年代 1:3Eden和Survivor比例调优
-XX:SurvivorRatio8 # Eden:Survivor 8:1GC日志配置
详细的GC日志是调优的基础
# JDK 8及以下
-XX:PrintGC
-XX:PrintGCDetails
-XX:PrintGCTimeStamps
-XX:PrintGCApplicationStoppedTime
-Xloggc:/path/to/gc.log# JDK 9
-Xlog:gc*:gc.log:time,tags监控指标关注点
GC频率每分钟GC次数GC停顿时间平均和最大停顿时间内存使用率各代内存使用情况吞吐量应用线程时间占比
故障排查实战案例
案例1CMS的并发模式失败
现象
[GC [1 CMS-initial-mark: 6656K(13696K), 0.0023781 secs]
[Full GC 6656K-6571K(13696K), 0.0577079 secs]原因CMS并发收集失败退化为Serial Old收集
解决方案
# 降低CMS触发阈值
-XX:CMSInitiatingOccupancyFraction60# 增加并发线程数
-XX:ConcGCThreads6案例2G1的to-space exhausted
现象
[GC pause (G1 Evacuation Pause) (to-space exhausted), 0.1234567 secs]原因G1无法找到足够的空Region来存放存活对象
解决方案
# 增加堆内存或调整Region大小
-Xmx16g
-XX:G1HeapRegionSize32m# 提前触发混合收集
-XX:G1MixedGCCountTarget4案例3频繁Full GC
排查步骤
分析GC日志确认Full GC频率检查内存分配模式分析对象生命周期调整堆内存比例
常见解决方案
# 增加堆内存
-Xms16g -Xmx16g# 调整新生代比例
-XX:NewRatio2# 增加Survivor空间
-XX:SurvivorRatio6高级调优技巧
1. 使用GC分析工具
推荐工具
GCViewer可视化GC日志分析GCPlot在线GC日志分析jstat实时GC监控
使用示例
# 监控GC情况
jstat -gc -t 12345 1s# 查看堆内存分布
jstat -gccapacity 123452. JIT编译优化
# 预热JIT编译器
-XX:CompileThreshold10000# 启用分层编译
-XX:TieredCompilation3. 大对象处理
# G1大对象阈值设置
-XX:G1HeapRegionSize32m # 大对象阈值为16m# 启用大对象直接分配到老年代
-XX:PretenureSizeThreshold1m未来趋势展望
1. Project Leyden
Oracle正在开发的项目旨在提供静态编译和快速启动能力。
2. Project Loom
虚拟线程项目将改变并发编程模式可能影响GC策略。
3. 分代ZGC
ZGC正在开发分代收集功能有望进一步提升性能。
总结与建议
经过这次深入的探讨我想给大家几个关键建议
1. 选择原则
小堆4GBParallel GC 或 G1 GC中堆4-32GBG1 GC大堆32GBZGC 或 Shenandoah延迟敏感G1、ZGC、Shenandoah吞吐量优先Parallel GC
2. 调优步骤
建立基准测试收集GC日志分析性能指标逐步调整参数验证改进效果
3. 最佳实践
始终监控GC性能定期分析GC日志保持对新技术的关注在非生产环境充分测试
4. 常用配置模板
Web应用推荐配置
-Xms8g -Xmx8g
-XX:UseG1GC
-XX:MaxGCPauseMillis100
-XX:G1HeapRegionSize16m
-XX:G1UseAdaptiveIHOP
-XX:G1MixedGCCountTarget8
-Xlog:gc*:gc.log:time,tags高并发服务配置
-Xms16g -Xmx16g
-XX:UseZGC
-XX:UnlockExperimentalVMOptions
-Xlog:gc*:gc.log:time,tags回到文章开头的那次生产故障经过这次系统性的学习和实践我们最终选择了G1垃圾回收器并通过精细的参数调优将系统的响应时间稳定在了50ms以内再也没有出现过类似的问题。
垃圾回收器的选择和调优是一门艺术需要理论知识与实践经验的完美结合。希望这篇文章能够帮助大家在JVM调优的道路上少走弯路打造更加稳定高效的Java应用。
记住没有银弹只有最适合的方案。在实际工作中一定要结合具体的业务场景和性能要求来选择合适的垃圾回收器并持续监控和优化。 如果这篇文章对你有帮助欢迎点赞分享。在垃圾回收器调优的路上我们一起进步