GC tuning

张开发
2026/4/8 21:01:54 15 分钟阅读

分享文章

GC tuning
一、什么是垃圾在Java中‌垃圾指的是堆内存中那些已经不再被任何引用链访问到的对象‌。这些对象无法再被程序使用其所占用的内存空间应当被回收以供新对象分配使用。例如Object obj new Object(); obj null;当obj被置为null后若该对象无其他引用指向它则成为“垃圾”。二、如何查找垃圾—— 垃圾判定算法JVM通过以下两种主要方式判断对象是否为垃圾‌引用计数法Reference Counting‌每个对象维护一个引用计数器当有引用时1引用失效时-1。计数为0即为垃圾。❌ 缺点无法解决‌循环引用‌问题如A引用BB引用A但外部已无引用。‌可达性分析算法GC Roots Tracing‌从一组称为“GC Roots”的根对象出发向下搜索引用链。‌无法被访问到的对象‌即为垃圾。✅ Java主流JVM如HotSpot采用此方法。‌常见的GC Roots包括‌虚拟机栈中的局部变量方法区中的静态变量常量池中的引用本地方法栈中的JNI引用三、如何清理垃圾—— 垃圾回收算法找到垃圾后JVM使用不同算法进行回收‌标记-清除Mark-Sweep原理先标记存活对象再清除未标记对象优点实现简单缺点两次扫描产生内存碎片适用于老年代存活对象较多‌复制算法Copying原理将存活对象复制到另一块区域清空原区域优点无碎片效率高缺点内存利用率低仅用一半移动对象指针用于新生代存活对象少标记-压缩Mark-Compact原理标记后将存活对象向一端移动清理边界外空间优点无碎片内存紧凑缺点两次扫描移动对象指针适用于老年代存活对象较多四、Java内存分代模型基于“弱分代假说”多数对象朝生夕死JVM将堆内存分为新生代Young Generation‌Eden区‌新对象首先分配在此Survivor区S0/S1‌经历一次GC后存活的对象转移至此使用‌复制算法‌GC频繁Minor GC老年代Old Generation存放长期存活的对象使用‌标记-清除或标记-压缩算法GC较少但耗时长Major GC / Full GC‌永久代/元空间Metaspace存储类信息、常量、静态变量等JDK 8后元空间取代永久代五、常见垃圾回收器不同回收器适用于不同场景Serial‌适用代新生代特点单线程简单高效适用场景客户端应用、单CPU环境Parallel Scavenge‌适用代新生代特点多线程追求高吞吐量适用场景后台计算型服务CMSConcurrent Mark Sweep‌适用代老年代特点并发收集低停顿适用场景响应时间敏感系统G1Garbage First‌适用代整堆特点分区管理可预测停顿适用场景大内存、低延迟服务ZGC / Shenandoah‌适用代整堆特点超低延迟10ms适用场景实时系统、金融交易六、常见调优参数‌JVM垃圾回收器的选择需根据应用的堆大小、延迟要求、吞吐量目标及JDK版本综合决策‌。以下是主流垃圾回收器的选型指南结合典型场景、核心参数与调优建议帮助你精准匹配业务需求。一、主流垃圾回收器选型决策树堆大小延迟要求推荐回收器适用JDK版本 1GB不敏感‌Serial GC‌所有版本1GB ~ 4GB不敏感‌Parallel GC‌JDK 8默认4GB ~ 32GB 200ms‌G1 GC‌JDK 9默认 32GB 或 10ms超低延迟‌ZGC / Shenandoah‌JDK 11ZGC、JDK 12Shenandoah✅ ‌通用建议‌JDK 8‌优先使用 ‌G1 GC‌ 替代默认的 Parallel GC以降低停顿时间 。‌JDK 9‌‌G1 GC‌ 为默认适合大多数服务 。‌JDK 11‌对延迟敏感场景直接选用 ‌ZGC‌ 。二、各回收器详解与调优建议‌G1 GCGarbage-First‌ —— 大内存与低延迟平衡之选适用场景‌微服务、Web API、堆内存 4GB~128GB 的生产环境 。核心优势‌可预测停顿时间、无内存碎片、分区域回收。关键参数-XX:UseG1GC启用 G1 回收器-XX:MaxGCPauseMillis200目标最大停顿时间JVM 自动调整-XX:InitiatingHeapOccupancyPercent40堆占用 40% 时触发并发标记-XX:G1HeapRegionSize16mRegion 大小1MB~32MB2 的幂调优建议避免频繁 Full GC合理设置 IHOP监控并发标记是否及时完成 。禁用显式 GC-XX:DisableExplicitGC 防止 System.gc() 触发 Full GC。启用字符串去重-XX:UseStringDeduplication 减少内存占用JDK 8。ZGCZ Garbage Collector‌ —— 超低延迟王者‌适用场景‌金融交易、实时竞价、堆内存 32GB要求停顿 10ms 。‌核心优势‌几乎全程并发STW 时间极短亚毫秒级。‌关键参数‌-XX:UseZGC启用 ZGCJDK 11-XX:ZHeapSize64g设置堆大小可选-XX:ZUncommit释放未使用内存避免长期占用‌调优建议‌确保操作系统支持Linux 需内核 5.6开启透明大页THP。监控 ZGC 日志使用 -Xlog:gc* 查看停顿时间与并发阶段耗时。Parallel GC吞吐量优先‌适用场景‌批处理、数据计算、后台任务追求高吞吐量 。‌核心优势‌多线程并行回收最大化 CPU 利用率。‌关键参数‌-XX:UseParallelGC新生代并行回收-XX:UseParallelOldGC老年代并行回收-XX:ParallelGCThreads8GC 线程数建议等于 CPU 核心数-XX:MaxGCPauseMillis200目标停顿时间不保证‌调优建议‌固定堆大小-Xms4g -Xmx4g 避免动态扩容 。启用自适应策略-XX:UseAdaptiveSizePolicy 自动调整分代比例。CMS GC已废弃仅 JDK 8 可用‌适用场景‌JDK 8 下低延迟需求但建议尽快迁移到 G1 或 ZGC 。‌关键参数‌-XX:UseConcMarkSweepGC启用 CMS-XX:CMSInitiatingOccupancyFraction75老年代占用 75% 时触发-XX:UseCMSInitiatingOccupancyOnly严格按阈值触发‌风险提示‌内存碎片易导致 Full GCJDK 9 起已废弃 。三、通用调优实践固定堆大小生产环境务必设置 -Xms 与 -Xmx 相同避免动态扩容引发 GC 。‌启用 GC 日志-Xlog:gc*:filegc.log:time,tags,uptime,level使用 GCViewer 或 GCEasy 分析。‌监控与诊断工具jstat -gc 1s实时查看 GC 频率与堆使用jmap -heap 查看堆配置与使用情况jcmd GC.run手动触发 GC仅调试避免常见陷阱不要过度调优每次只调整 1~2 个参数观察效果 。大对象直接晋升-XX:PretenureSizeThreshold1m 避免在新生代频繁复制。元空间限制-XX:MaxMetaspaceSize512m 防止元空间无限增长。

更多文章