ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

hostspot的默认垃圾回收器

hostspot的默认垃圾回收器 JVM GC 停顿问题学习笔记一、核心结论速记JDK 1.8 中所有收集器的 Young GC 都是 STW 的区别只在停顿时长与可控性“并行”≠“并发”并行是多个 GC 线程同时干活应用仍暂停并发是 GC 与应用线程同时运行CMS/G1 的“并发”只覆盖标记阶段移动对象在它们那里永远需要全停顿ZGC 是唯一做到并发移动对象的停顿亚毫秒级且与堆大小无关但 JDK 1.8 用不了默认收集器主线只有一次换乘8 及以前默认 Parallel9 起至今含 17/21/25一律默认 G1ZGC/Shenandoah 从未成为任何版本的默认必须显式开启“默认”由版本 运行环境自动裁定Ergonomics 机制启动后不随负载切换默认 ≠ 最优低延迟服务要主动换收集器一句话主线标记可以并发写屏障就够移动对象要并发必须有读屏障——这是 JDK 1.8 收集器与 ZGC 的分水岭二、版本默认收集器全景结合页面内容含勘误JDK 版本默认 GC服务器级核心算法并发能力备注≤ 8Parallel Scavenge Parallel Old新生代复制 老年代标记整理无全程 STW服务器级判定≥2 核且 ≥2GB否则降级 Serial Serial Old9 ~ 22G1Region 化标记整理并发标记转移 STWJEP 248 起默认JDK 14 移除 CMS23 ~ 24G1同上同上选用 ZGC 时默认走分代模式JEP 47424 移除非分代 ZGC25G1同上同上JEP 523 让 G1 成为包括小内存容器在内所有配置的默认Shenandoah 分代转正三个要点服务器级与非服务器级的分野JDK 8 特有。JVM 启动时会按机器规格自动选默认收集器物理内存 ≥2GB 且 CPU 核数 ≥2 的“服务器级机器”默认 Parallel吞吐量优先否则退回 Serial。这是 Ergonomics 自适应机制的一部分与版本一起决定“你什么都没配时用的是谁”。腾讯云开发者社区G1 的四阶段页面内容整合初始标记STW短只标 GC Roots 直达对象→ 并发标记与应用同跑做可达性分析→ 最终标记STW短补标并发期间用户线程改动过的引用——这正是 SATB 写屏障的产出落点→ 筛选回收按各 Region 的回收价值/成本排序在-XX:MaxGCPauseMillis预算内制定回收集。注意筛选回收即 Evacuation本身仍是 STW——与下文“移动不能并发”呼应。勘误不存在“19 默认 ZGC/Shenandoah”。真实的演进是G1 从 9 起一直是默认17、21 两个 LTS 未变25 仍是坊间误传可能混淆了两件事——ZGC 在 23JEP 474只是“当你选用 ZGC 时默认启用分代模式”24 进一步移除非分代模式两者说的都是 ZGC 内部的默认不是 JVM 全局默认。ZGC/Shenandoah 任何版本都需-XX:UseZGC/-XX:UseShenandoahGC显式开启。三、为什么 Young GC 一定 STWYoung GC 采用复制算法把 Eden Survivor 的存活对象搬到另一个 Survivor 或老年代然后整块清空。这个过程的两个动作都无法与应用线程共存复制对象应用线程可能正通过旧地址读写对象搬一半就产生脏数据修正引用所有指向搬家对象的引用包括线程栈局部变量、老年代字段里的 old-to-young 指针都要改写而这些引用正被应用使用所以只能全停 GC 独占执行。Young GC 快是因为新生代小、存活对象少大部分朝生夕死、多 GC 线程并行——快但仍然是停的。这也解释了为什么 Parallel/G1 的默认 Young GC 都是停顿型区别只是 G1 把停顿做成可预算的。四、为什么“标记”可以并发“移动”不行对比项并发标记并发移动对象本质对对象图的只读遍历修改堆布局 改写所有引用难点漏标/错标可用快照修正旧地址失效应用无感知机制所需技术写屏障CMS 用增量更新G1 用 SATB读屏障 转发指针JDK 1.8 是否具备有没有写屏障只在引用赋值时插入少量指令开销可摊薄读屏障要拦截每一次引用读取频率高一个量级JDK 1.8 的 HotSpot 没有实现。这就是边界所在。五、老年代“并发”的真相以 CMS 为例CMS 流程初始标记STW短→ 并发标记 → 重新标记STW短→ 并发清除。它用的是标记-清除全程不移动对象所以能并发代价是内存碎片碎片满了触发 Full GCSerial Old 整理秒级 STW——证明“移动对象”它也做不到并发补充时间线JDK 8 中 CMS 需-XX:UseConcMarkSweepGC显式开启默认老年代收集器是 Parallel Old且新生代只能配 ParNew 或 Serial不能配 Parallel Scavenge线程接管接口不兼容——收集器是成对的组合CMS 于 JDK 9 弃用、14 移除结论老年代是用碎片化换并发性并非有什么魔法摆脱停顿维度Parallel OldCMS算法标记-整理移动对象标记-清除不移动对象并发性无全程 STW标记、清除与应用并发仅两次短 STW单次停顿长老年代一次性整堆处理短初始标记 重新标记通常毫秒级吞吐量高GC 独占 CPU无干扰低并发线程与应用抢 CPU内存碎片无有积累后被迫压缩浮动垃圾无全停期间标记即准确有并发清除期间新产生的垃圾本轮回收不掉失败模式无特殊退化Concurrent Mode Failure → 退化为 Serial Old触发时机被动老年代分配不下了才回收主动占用率达到阈值即启动并发周期新生代搭档Parallel ScavengeParNew或 Serial配不了 Parallel Scavenge设计目标吞吐量优先停顿时间优先六、G1 与 ZGC 的能力对照维度G1ZGCYoung GC 是否 STW是全程停顿Evacuation Pause否并发转移仅极短标记停顿移动对象并发不能只有写屏障能着色指针 读屏障 转发表停顿量级几十毫秒可控可预测亚毫秒级与堆大小无关关键机制Region 化 停顿预测模型 -XX:MaxGCPauseMillis着色指针Marked0/Marked1/Remapped 读屏障自愈 多重映射版本JDK 7u4 引入9 起默认且延续至 251.8 可用11 实验引入15 转正1.8 不可用分代分代21 起支持分代可选23 选用即默认分代24 起仅剩分代是否需要显式开启否9 默认是任何版本都要-XX:UseZGCG1 的正确定位停顿可控而非停顿消除。它把回收拆成 Region 粒度按历史耗时预测在预算内能装多少 Region垃圾多的优先Garbage First。Mixed GC 里搬老年代 Region 同样是 STW 的。它成为 9 之后长期默认正是因为“可控停顿 够用吞吐”最普适。ZGC 的关键三件套着色指针把 GC 阶段信息编码进地址读屏障在应用读引用时发现对象已搬家就查转发表自动纠偏自愈多重映射让旧地址也能看到新对象。于是“搬对象”不再需要暂停所有人。七、选型与调优备忘困在 JDK 1.8ZGC 无缘G1 是停顿可控的唯一选择-XX:UseG1GC-XX:MaxGCPauseMillis目标值注意默认组合是 Parallel要换必须显式指定别赌默认值JDK 25 之前的小容器2 核或 2GB会踩中 Ergonomics 的“Serial 陷阱”容器环境确认-XX:UseContainerSupport生效8u191 引入必要时-XX:ActiveProcessorCount修正核数判定验证当前用的是谁java -XX:PrintCommandLineFlags -version看输出的Use*GC标志9 也可用-Xlog:gc启动即打印运行中进程用jcmd pid VM.flags观察停顿JDK 8 用-XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:gc.log看Pause Young的实际秒数9 统一为-Xlog:gc*:filegc.logYoung GC 过长的调优方向减小新生代/Eden、增大-XX:ParallelGCThreads、换 G1 并设目标停顿升级 JDK 前做参数体检CMS 相关参数在 14 直接失效收集器参数与 JDK 版本要成套迁移硬延迟场景交易、实时风控出路是升级 JDK 17/21 换 ZGC-XX:UseZGC代价是吞吐量比 G1 低个位数百分比——拿吞吐换延迟补充Shenandoah 有非官方 JDK 8 backport且 Oracle JDK 不自带需 Red Hat/OpenJDK 系构建生产环境慎用优先升级 JDK八、一条逻辑主线从版本默认看是两步走8 及以前吞吐优先的 Parallel机器不够格就 Serial9 起换成停顿可控的 G1并且这个默认一直延续到 25 没再变过——ZGC、Shenandoah 始终要显式开启。从停顿原理看是一条能力边界线复制算法要求移动对象并修正引用 → 应用线程无法感知对象搬家 → 要并发就需要读屏障 → JDK 1.8 只有写屏障 → 所以 CMS/G1 的 Young GC 只能 STWCMS 靠“不移动对象”换取老年代并发标记清除代价是碎片→ ZGC 引入着色指针 读屏障 转发表第一次让移动对象也能并发停顿与堆大小无关——想用它的唯一路径是升级 JDK。下面是老内容没有删除在 Java 中HotSpot 虚拟机默认的垃圾回收器Garbage Collector, GC取决于 Java 版本和运行环境。以下是不同 Java 版本中 HotSpot 虚拟机的默认垃圾回收器Java 8 及更早版本并行垃圾回收器Parallel GC在 Java 8 及更早版本中HotSpot 虚拟机的默认垃圾回收器是并行垃圾回收器也称为吞吐量垃圾回收器。它使用多线程进行年轻代和老年代的垃圾回收适合多核处理器环境。新生代使用标记复制算法老年代使用标记整理算法Java 9 到 Java 18G1 垃圾回收器Garbage-First GC从 Java 9 开始HotSpot 虚拟机的默认垃圾回收器变为 G1 垃圾回收器。G1 是一种面向服务端应用的垃圾回收器旨在提供更可预测的停顿时间低延迟和更高的吞吐量。该垃圾收集器把堆划分成多个大小相等的独立区域Region来进行垃圾回收并且可以动态调整区域的大小空间可以单独进行垃圾回收。初始标记标记与GC roots直接关联的对象。并发标记可达性分析。最终标记对并发标记过程中用户线程修改的对象再次标记一下。筛选回收对各个Region的回收价值和成本进行排序然后根据用户所期望的GC停顿时间制定回收计划并回收。Java 19 及更高版本ZGCZ Garbage Collector或Shenandoah GC在某些情况下Java 19 及更高版本可能会默认使用 ZGC 或 Shenandoah GC具体取决于运行环境和配置。ZGC 和 Shenandoah 都是低延迟垃圾回收器旨在将停顿时间控制在毫秒级别适合对延迟敏感的应用。如何查看当前使用的垃圾回收器你可以通过以下命令查看当前 Java 虚拟机使用的垃圾回收器java-XX:PrintCommandLineFlags-version输出中会显示当前使用的垃圾回收器相关的 JVM 参数。总结Java 8 及更早版本默认使用Parallel GC。Java 9 到 Java 18默认使用G1 GC。Java 19 及更高版本可能默认使用ZGC或Shenandoah GC具体取决于配置。如果你有特定的性能需求可以根据应用场景选择合适的垃圾回收器并进行配置。
返回列表