ARTICLE DETAIL

资讯详情

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

java中的垃圾回收器

java中的垃圾回收器 垃圾回收器垃圾回收集器分新生代收集器、老年代收集器、组合收集器JDK8 默认Parallel Scavenge Parallel OldJDK9 开始默认 G1新生代Serial串行收集器单线程STW标记复制。适用客户端、单核小应用。缺点STW 时间长。启动参数-XX:UseSerialGCParallel ScavengePS并行回收多线程标记复制。目标吞吐量优先。吞吐量 运行用户代码时间 / (用户代码 GC 时间)。搭配老年代Parallel Old。参数-XX:UseParallelGCParNew多线程标记复制。和 PS 算法一样但可以和 CMS 配合PS 不能和 CMS 搭配。JDK8 以前 CMS 默认新生代收集器。参数-XX:UseParNewGC老年代Serial Old单线程标记整理。用途客户端CMS 失败时的降级备用收集器。Parallel Old多线程标记整理吞吐量优先。搭配 PS。JDK8 默认组合PS Parallel Old。CMSConcurrent Mark Sweep并发标记清除低延迟并发标记 清除会产生内存碎片。阶段初始标记 (STW) → 并发标记 → 重新标记 (STW) → 并发清除缺点内存碎片Full GC 后需要整理浮动垃圾并发失败Concurrent Mode Failure触发 Full GC退化 Serial Old占用 CPU。JDK9 开始废弃 CMS。参数-XX:UseConcMarkSweepGC整堆收集器新生代 老年代一起回收G1Garbage-First分区模型Region不再严格分新生代老年代可预测停顿。算法标记整理整体无碎片局部标记复制。目标兼顾吞吐量和低延迟。优先回收垃圾最多的 Region。JDK9 默认 GC。参数-XX:UseG1GCZGCZ Garbage CollectorJDK11 引入JDK15 正式启用。目标极低延迟STW 几乎 ms 级。染色指针读屏障几乎全并发。最大堆支持 TB 级。几乎没有 STW。JDK17 推荐生产使用。参数-XX:UseZGCShenandoahRedHat 开发和 ZGC 类似低延迟不需要移动对象时的读屏障用转发指针。JDK12 引入OpenJDK。对比表收集器代算法特点目标缺点Serial新生标记复制单线程简单小内存STW 长Parallel Scavenge新生标记复制多线程吞吐量优先停顿时间不可控ParNew新生标记复制多线程配合 CMS已慢慢淘汰Serial Old老年标记整理单线程兜底回收STW 很长Parallel Old老年标记整理多线程吞吐量优先停顿不可控CMS老年标记清除并发低延迟碎片、并发失败JDK9 废弃G1整堆标记整理 复制分区 Region可控停顿大堆场景性能不如 ZGCZGC整堆染色指针全并发亚毫秒级 STWCPU 消耗略高Shenandoah整堆转发指针全并发低延迟生态不如 ZGC 成熟垃圾回收器执行流程CMS(Concurrent Mark Sweep并发标记清除)CMS 是老年代收集器目标低延迟尽量并发减少 STW算法标记清除会产生内存碎片。搭配新生代ParNew。JDK9 开始废弃。核心只有两个阶段 STW其余阶段 GC 线程和业务线程并发执行初始标记-并发标记-重新标记-并发清除1. 初始标记Initial Mark【STW很短】只标记GC Roots 直接可达的对象第一层对象不会递归遍历整个对象图。暂停所有用户线程。因为只扫根直接引用速度很快。2. 并发标记Concurrent Mark【并发无 STW】GC 线程和业务线程同时运行。从初始标记得到的根对象开始递归遍历整个老年代对象图标记所有存活对象。⚠️ 并发阶段业务线程还在修改引用会产生漏标问题。CMS 使用增量更新方案解决漏标如果黑色对象新增指向白色对象的引用写屏障把这个黑色对象记录到灰色栈留到 Remark 阶段重新扫描。3. 重新标记Remark【STW时间波动大】处理并发标记阶段产生的漏标对象。扫描灰色栈里记录的对象重新遍历它们的引用补标记存活对象。这个阶段 STW 时间不确定如果并发阶段大量新增引用灰色栈很大STW 会明显变长。4. 并发清除Concurrent Sweep【并发无 STW】GC 线程和业务线程并发运行。遍历堆把未被标记的对象当成垃圾直接回收不移动存活对象。算法是标记清除不会整理内存会产生内存碎片。G1Garbage-FirstG1Garbage-First分区 Region 模型整堆收集器目标可预测停顿。GC 分为两类Young GC、Mixed GC尽量避免 Full GCFull GC 是退化单线程 Serial OldSTW 很长G1 采用SATB 原始快照解决三色标记漏标。Young GC年轻代回收触发条件Eden 区耗尽。STW暂停业务线程标记 Eden、Survivor 里存活对象复制存活对象到 Survivor Region对象年龄增加达到阈值晋升到老年代 Region清空 Eden只回收年轻代 Region不处理老年代Mixed GC 的初始标记会依附在 Young GC 末尾复用这次 STW减少一次停顿Mixed GC混合 GCG1 核心老年代占比达到 IHOP 阈值触发一次性回收部分年轻代 部分垃圾最多的老年代 Region一共 4 个阶段初始标记Initial Mark【STW】依附在 Young GC 之后复用 STW。只标记 GC Roots直接可达对象。并发标记Concurrent Mark【并发业务线程继续跑】GC 线程和用户线程并发从初始标记的对象遍历整个堆标记存活对象。当业务线程删除 / 覆盖引用SATB 写屏障会把旧对象压入 SATB 队列防止漏标。产生浮动垃圾快照时刻存活但并发阶段已经失效的对象本次 GC 不能回收。最终标记Remark【STW】短暂暂停处理 SATB 队列剩余对象完成全部存活对象标记。筛选回收Cleanup Evacuation【STW】① 对所有 Region 按垃圾占比排序② 根据-XX:MaxGCPauseMillis目标停顿时间挑选垃圾最多的一批 Region③复制存活对象到空闲 RegionEvacuation 转移④ 清空这批 Region。因为是复制存活对象所以不会产生内存碎片。⚠️ Mixed GC ≠ Full GCMixed GC 只挑选部分老年代 Region 回收不是全部老年代。G1如何解决三色指针漏标问题G1 使用SATB 写屏障解决三色标记漏标问题。SATB 的核心思想在初始标记完成那一刻拍一个逻辑快照凡是快照时刻存活的对象本轮 GC 一律当成存活不允许被漏标回收。漏标必要条件黑色对象新增引用指向白色对象灰色对象指向该白色对象的全部引用被删除SATB 写屏障只拦截「引用删除 / 覆盖」操作。当业务线程执行obj.field null或者覆盖旧引用判断被删除的旧引用指向的对象是否是快照内对象地址 ≤ TAMS如果是快照内对象 → 把这个对象压入SATB 队列如果是快照后新建对象TAMS→ 不处理重点SATB不捕获新增引用只捕获删除快照内对象的引用。TAMSTop At Mark Start标记开始时的 Region 分配顶指针G1 专属在Mixed GC 初始标记完成瞬间给每一个 Region 记录下当时 Region 的top值。先搞懂 Region 里的两个指针bottomRegion 内存起始地址top对象分配游标新对象从 top 往后分配top 前面是已经分配的对象top 后面是空闲空间。Region 内存bottom | 已分配对象 | top | 空闲空间 | endTAMS 的作用在初始标记完成快照点G1 对每个 Region 保存TAMS 当前Region.top以此划分 Region 内两类对象对象地址 ≤ TAMS快照前分配的对象快照内对象SATB 保护范围。删除这类对象的引用写屏障会把对象压入 SATB 队列。对象地址 TAMS快照之后并发标记阶段新建的对象快照外对象不受 SATB 保护。删除它的引用写屏障不做任何处理。✅ G1 判断对象是否属于快照内对象底层就是比较对象地址和所属 Region 的 TAMS。ZGC(Z Garbage Collector)ZGC低延迟并发垃圾收集器目标亚毫秒级 STW堆可以支持 TB 级。核心技术染色指针Colored Pointers 读屏障Load BarrierZGC 是并发标记 并发转移复制全程几乎不 STW。ZGC 没有分代不区分新生代老年代没有 Region是 Page 页管理。三色标记保护读屏障和 G1 SATB、CMS 增量更新不一样。ZGC 一次 GC 分为 4 大阶段只有初始标记、再标记两个极短 STW 阶段STW 时间和堆大小无关只和 GC Roots 数量相关。1. 初始标记Pause Mark Start【STW极短】暂停所有业务线程。只扫描GC Roots标记 Root 直接可达对象。✅ STW只找根不递归遍历对象图。2. 并发标记Concurrent Mark【并发业务线程正常跑】GC 线程和业务线程并发执行。从 Root 对象开始遍历整个对象图标记存活对象。读屏障发挥作用业务线程读取对象引用时触发读屏障检查指针染色状态如果对象正在被移动读屏障会转发到新地址保证拿到正确对象。ZGC 靠读屏障解决并发标记时的对象引用变化问题。3. 再标记Pause Mark End【STW极短】短暂 STW处理并发标记阶段遗留的少量引用完成存活对象标记。这是第二轮 STW时间很短。标记阶段到此结束。4. 并发转移Concurrent Relocate【并发业务线程正常跑】ZGC 挑选垃圾多的 Page准备回收。并发把存活对象复制转移到新 Page类似复制算法。对象复制完成后旧对象指针保留染色标记后续业务线程访问旧地址时读屏障自动转发到新对象地址等所有引用都更新到新地址旧 Page 直接释放回内存。转移全程并发不会 STW。补充并发转移完成后还有一个并发重置Concurrent Reset重置 Page为下一轮 GC 做准备并发执行。ZGC如何解决三色指针漏标问题ZGC 使用「读屏障 染色指针Colored Pointers」来解决并发标记漏标采用的是读快照Load Barrier方案。ZGC 要保证标记开始那一刻存活的对象本轮 GC 一定全部标记不能漏。ZGC 核心染色指针Colored PointerZGC 在对象引用指针本身借用地址高位几个 bit 存标记状态Marked0Marked1Remapped不是对象头是指针本身。所以 ZGC 要求操作系统是64位且堆不能超过 4TB否则地址位不够。通过染色指针ZGC 可以不用去对象头直接从指针就能判断对象标记状态。ZGC 的读屏障Load BarrierZGC 没有写屏障G1/CMS 是写屏障ZGC 用读屏障。读屏障每当业务代码读取对象引用的时候触发一小段逻辑。当线程读取引用obj.field读屏障会检查如果这个指针是未标记的快照内对象白色立刻把这个对象标记成存活并且递归标记它的子对象。ZGC并发标记核心规则ZGC 在标记开始选定本轮标记版本Marked0 / Marked1二选一交替使用。对象在标记开始前分配对象引用指针上没有本轮标记版本 →快照前对象本轮需要标记保护防止漏标。对象在标记开始之后分配分配的时候直接把这个新对象的指针标记为本轮已标记Marked0/Marked1。新对象出生即标记为存活本轮 GC 不会去扫描、回收它直接交给下一轮 GC。标记举例GC 周期 A 启动选择本轮标记版本Marked0标记开始前对象 C 已经分配指针无 Marked0 标记 →快照内对象并发标记期间业务 new 对象 B分配时直接打上Marked0→快照后对象读屏障读到 CC 没有 Marked0属于快照内对象如果白色就标记存活读屏障读到 BB 自带 Marked0快照后对象直接放行不处理等到下一轮 GC 周期 B切换标记版本为Marked1。此时 B 上面的 Marked0 就不再是本轮标记B 就变成本轮快照内对象。怎么防止漏标漏标发生的根源业务删掉灰色引用同时黑色新增指向白色快照对象GC 看不到。在 ZGC只要业务线程读取这条黑色对象指向白色对象的引用读屏障就触发当场把白色对象标记存活。 只要这条引用被业务访问一次对象就被标记不会丢失。ZGC 的快照承诺标记开始时存活的对象本轮必须保留。标记开始之后新创建的对象本轮 GC 完全不处理全部留给下一轮 GC和 G1 不一样。
返回列表