邯郸市建设局网站辽宁建设工程信息网场内业绩

当前位置: 首页 > news >正文

邯郸市建设局网站,辽宁建设工程信息网场内业绩,中小型企业网站建设与推广,给别人做网站 网站违法了文章目录前言一、思考问题二、官方文档三、基本介绍四、G1的内存模型五、G1的标记过程六、G1的垃圾回收1、G1过程梳理2、Young GC3、Mixed GC4、Full GC七、参数介绍八、典型问题1、疏散失败#xff08;Evacuation Failure#xff09;2、大对象分配#xff08;Humongous All… 文章目录前言一、思考问题二、官方文档三、基本介绍四、G1的内存模型五、G1的标记过程六、G1的垃圾回收1、G1过程梳理2、Young GC3、Mixed GC4、Full GC七、参数介绍八、典型问题1、疏散失败Evacuation Failure2、大对象分配Humongous Allocation3、Young GC花费时间太长4、Mixed GC耗时太长总结前言 本来不准备写关于G1垃圾回收器的文章因为网上介绍的文章真的太多了写出来容易千篇一律有抄袭的嫌疑。 但由于最近工作中遇到了G1垃圾回收期的线上优化问题查找了很多资料最终还是决定做一个总结也希望能对大家有所帮助。 一、思考问题 先抛出一些关于G1垃圾回收器的问题如果你都能回答上来说明真的吃透了G1垃圾回收器那么这篇文章你可以跳过了。如果还存在疑问希望本文能给你解惑。 G1有哪些特点G1是分区还是分代G1的一个内存单元Region中可以同时包含年轻代和老年代吗G1相比CMS有哪些优点相比ZGC有什么缺点G1配置过程中有哪些重要参数和注意事项G1的使用过程中遇到过哪些问题怎么解决的G1怎么实现目标暂停时间的G1垃圾回收的过程中哪些阶段会出现STWG1中哪些情况对象会被转移到老年代Old Genetion?G1中触发GC的时机G1有哪些缺点G1的适用场景G1能否支持上T的大内存G1在哪些情况下会出现Full GC? 二、官方文档 官网https://www.oracle.com/technical-resources/articles/java/g1gc.html java8下的g1说明 java19下的g1说明 G1垃圾收集器详解 注意 推荐使用的是什么版本的JDK就查看对应版本的官网文档说明因为不同版本间的一些参数可能会有些细微的不同。由于目前主流还是使用java8所以本文主要基于java8来对g1垃圾回收器展开介绍。 三、基本介绍 G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一。早在JDK7就已加入JVM的收集器大家庭中成为HotSpot重点发展的垃圾回收技术JDK9 默认就是使用的G1垃圾收集器。 G1其实是Garbage First的意思垃圾优先? 不是是优先处理那些垃圾多的内存块的意思。 Garbage-First (G1)垃圾收集器是一个服务器风格的垃圾收集器针对具有大内存的多处理器机器它试图在实现高吞吐量的同时以较高的概率满足垃圾收集(GC)暂停时间目标。 G1中堆被划分为一组大小相等的堆区域每个区域有一个连续的虚拟内存范围。G1执行并发全局标记阶段以确定整个堆中对象的活性。在标记阶段完成后G1知道哪些区域大部分是空的。它首先收集这些区域这往往会产生大量的自由空间。这就是为什么这种垃圾收集方法被称为“垃圾优先”。 顾名思义G1将其收集和压缩活动集中在堆中可能充满可回收对象(即垃圾)的区域。G1使用暂停预测模型来满足用户定义的暂停时间目标并根据指定的暂停时间目标选择要收集的区域数。 G1将对象从堆的一个或多个区域复制到堆的单个区域并在进程中压缩和释放内存。这种疏散是在多处理器上并行执行的以减少暂停时间并提高吞吐量。因此对于每次垃圾收集G1都会持续地减少碎片。 需要注意的是G1并不是一个实时收集器。它满足设定的暂停时间目标具有较高的概率但不是绝对确定的。根据以前收集的数据G1估计在目标时间内可以收集多少个区域。因此收集器拥有一个相当精确的区域收集成本模型并使用该模型来确定在暂停时间目标内收集哪些区域以及收集多少个区域。 G1的第一个重点是为运行需要大堆且 GC 延迟有限的应用程序的用户提供解决方案。这意味着堆大小约为6 GB 或更大并且稳定且可预测的暂停时间低于0.5秒。 注意在Java19推荐10G或者更大的堆内存 如果应用程序具有以下一个或多个特性那么当今使用 CMS 或并行压缩运行的应用程序将从切换到 G1中受益。 堆内存超过6G且活跃的数据超过java堆内存的50%对象分配和晋升的速度非常快应用程序不希望垃圾回收或内存压缩的暂停时间超过0.5s到1s G1和CMS有哪些区别 G1被计划作为并发标记扫描收集器(CMS)的长期替代品通过比较 G1和 CMS 的差异可以帮助我们更好的理解G1并合理的选用。 1、空间压缩G1采用复制-整理算法在压缩空间方面有优势可以避免产生内存空间碎片而CMS采用标记-清除算法会产生较多的空间碎片 2、暂停时间的可控性G1使用暂停预测模型来满足用户定义的暂停时间目标并根据指定的暂停时间目标选择要收集的区域数。CMS无法设置目标暂停时间暂停时间不可控。 3、内存模型方面G1采用物理分区逻辑分代EdenSurvivorOld区不在是连续的一整块内存而是又不连续的内存区域Region组成。而CMS中EdenSurvivorOld区是连续的一整块内存。 4、G1既可以收集年轻代也可以收集老年代而CMS只能在老年代使用。 G1和ZGC比较 最核心的问题是G1未能解决复制-转移过程中准确定位对象地址的问题无法做到复制-转移过程的并行。 G1的优缺点 优点 1、支持较大的内存 2、暂停时间可控 3、压缩空间避免产生内存碎片 4、简单配置就能达到很好的性能 缺点 1、记忆集RSet会占用比较大的内存因此不建议在小内存下使用G1推荐至少6G 2、对CPU的负载可能会更大一点 3、由于采用复制算法GC垃圾回收过程对象复制转移会占用较多的内存更容易出现回收失败Allocation (Evacuation) Failure的问题。 4、可能会降低吞吐量 虽然 G1收集器的垃圾收集暂停时间通常要短得多但应用程序吞吐量也往往略低一些。相当于把一次垃圾回收的工作分开多次进行执行主要指老年代单次暂停的时间虽然更加可控但是由于每次垃圾回收的空间会更少总体来说垃圾回收的效率会更低暂停的总时间会更长所以吞吐量往往会略低一些。 四、G1的内存模型 G1 是一个既分区也分代的垃圾收集器这意味着 Java 对象堆(堆)被划分为许多大小相同的区域。在启动时Java 虚拟机(JVM)设置区域大小。根据堆大小区域大小可以从1MB 到32MB 不等。目标是不超过2048个地区。伊甸园、幸存者和老一代是这些区域的逻辑集合并不相邻。 由于分区的原因,G1可以只选取部分区域进行内存回收,这样缩小了回收的范围,因此对于全局停顿情况的发生也能得到较好的控制。G1 跟踪各个 Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。 G1的内存模型 说明 G1是物理分区逻辑分代 红色区域是年轻代 young generation包含伊甸区eden regions红色不带S区域和幸存区survivor regions 红色带S区域浅蓝色区域是老年代old generation,其中包含跨多个区域组成的大对象区域Humongous Region蓝色带H区域灰色区域表示空闲区free regions 传统的GC内存模型 传统的垃圾回收器把内存分成三类: Eden(E), Suvivor(S)、Old(O)和持久代。 Eden(E), Suvivor(S)属于年轻代Old(O)属于老年代且各区域的内存空间是连续的。 针对G1的内存模型中的补充说明 巨型对象Humongous Region 一个大小达到甚至超过分区大小一半的对象称为巨型对象(Humongous Object)。当线程为巨型对象分配空间时不能简单在TLAB进行分配因为巨型对象的移动成本很高而且有可能一个分区不能容纳巨型对象。因此巨型对象会直接在老年代分配所占用的连续空间称为巨型分区(Humongous Region)。 G1内部做了一个优化一旦发现没有引用指向巨型对象则可直接在年轻代收集周期中被回收。 巨型对象会独占一个、或多个连续分区其中第一个分区被标记为开始巨型(Starts Humongous)相邻连续分区被标记为连续巨型(Continues Humongous)。由于无法享受Lab带来的优化并且确定一片连续的内存空间需要扫描整堆因此确定巨型对象开始位置的成本非常高如果可以应用程序应避免生成巨型对象。 对于巨型对象有以下几个点需要注意 没有被引用的巨型对象会在标记清理阶段或者Full GC时被释放掉。 Young GC和Mixed GC阶段都会对巨型对象进行回收 巨型对象永远不会移动即使在Full GC中 每一个region中都只有一个巨型对象该region剩余的部分得不到利用会导致堆碎片化。 如果看到由于大对象分配导致频繁的并发回收需要把大对象变为普通的对象建议增大Region size或者切换到ZGC。但是增大Region size有一个负面影响就是减少了可用region的数量。因此对于这种情况你需要进行相应的测试以查看是否实际提高了应用程序的吞吐量或延迟。 在分配巨型对象之前会先检查是否超过 initiating heap occupancy percent和the marking threshold, 如果超过的话就启动global concurrent marking为的是提早回收防止 evacuation failures 和 Full GC。 记忆集合Remember Set (RSet) 在串行和并行收集器中GC通过整堆扫描来确定对象是否处于可达路径中。然而G1为了避免STW式的整堆扫描在每个分区记录了一个已记忆集合(RSet)内部类似一个反向指针记录引用分区内对象的卡片索引。当要回收该分区时通过扫描分区的RSet来确定引用本分区内的对象是否存活进而确定本分区内的对象存活情况。事实上并非所有的引用都需要记录在RSet中如果一个分区确定需要扫描那么无需RSet也可以无遗漏的得到引用关系。那么引用源自本分区的对象当然不用落入RSet中同时G1 GC每次都会对年轻代进行整体收集因此引用源自年轻代的对象也不需要在RSet中记录。最后只有老年代的分区可能会有RSet记录这些分区称为拥有RSet分区(an RSet’s owning region)。 注意⚠️每个区域Region都有一个记忆集RSet列出了从外部指向该区域的引用。RSet中的信息是实时维护的也就是每次产生外部引用都会立刻记录到RSet中而不需要等待GC时才产生。 收集集合 (CSet) 收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中CSet所有分区都会被释放内部存活的对象都会被转移到分配的空闲分区中。因此无论是年轻代收集还是混合收集工作的机制都是一致的。年轻代收集CSet只容纳年轻代分区而混合收集会通过启发式算法在老年代候选回收分区中筛选出回收收益最高的分区添加到CSet中。候选老年代分区的CSet准入条件可以通过活跃度阈值-XX:G1MixedGCLiveThresholdPercent(默认85%)进行设置从而拦截那些回收开销巨大的对象同时每次混合收集可以包含候选老年代分区可根据CSet对堆的总大小占比-XX:G1OldCSetRegionThresholdPercent(默认10%)设置数量上限。由上述可知G1的收集都是根据CSet进行操作的年轻代收集与混合收集没有明显的不同最大的区别在于两种收集的触发条件 五、G1的标记过程 当堆的整体占用足够大时并发标记开始。默认情况下它是45通过参数InitiatingHeapOccupancyPercent控制。 并发标记Concurrent Marking阶段主要是为Mixed GC做准备 G1的标记分为以下几个阶段:
1、初始标记 Initial marking phase 此阶段标志着从GC根直接到达的所有对象该阶段依赖于年轻代垃圾收集young gc该阶段是STW的。由于GC Roots数量不多通常该阶段耗时非常短。事实上当达到IHOP阈值时G1并不会立即发起并发标记周期而是等待下一次年轻代收集利用年轻代收集的STW时间段完成初始标记这种方式称为借道(Piggybacking)。 1.631: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0062656 secs]2、根区域扫描阶段 Root region scanning phase 扫描在初始标记阶段被标识的幸存区域标记那些被老年代引用的存活对象。此阶段与应用程序(而非 STW)并发运行必须在下一个 STW 年轻垃圾回收开始之前完成。 在初始标记暂停结束后年轻代收集也完成了对象复制到Survivor的工作应用线程开始活跃起来。此时为了保证标记算法的正确性所有新复制到Survivor分区的对象都需要被扫描并标记成根这个过程称为根分区扫描(Root Region Scanning)同时扫描的Suvivor分区也被称为根分区(Root Region)。根分区扫描必须在下一次年轻代垃圾收集启动前完成(并发标记的过程中可能会被若干次年轻代垃圾收集打断)因为每次GC会产生新的存活对象集合。 1.362: [GC concurrent-root-region-scan-start] 1.364: [GC concurrent-root-region-scan-end, 0.0028513 secs]3、并发标记阶段 Concurrent marking phase G1 GC 在整个堆中查找可访问的(活动的)对象。这个阶段与应用程序同时发生并且可以被 STW 年轻的垃圾回收中断。 1.364: [GC concurrent-mark-start] 1.645: [GC concurrent-mark-end, 0.2803470 secs]4、重标记阶段 Remark phase 重新标记(Remark)是最后一个标记阶段。在该阶段中G1需要一个暂停的时间STW去处理剩下的SATB日志缓冲区和所有更新找出所有未被访问的存活对象同时安全完成存活数据计算。这个阶段也是并行执行的通过参数-XX:ParallelGCThread可设置GC暂停时可用的GC线程数。同时引用处理也是重新标记阶段的一部分所有重度使用引用对象(弱引用、软引用、虚引用、最终引用)的应用都会在引用处理上产生开销最后还会执行一些类卸载操作。 1.645: [GC remark 1.645: [Finalize Marking, 0.0009461 secs] 1.646: [GC ref-proc, 0.0000417 secs] 1.646: [Unloading, 0.0011301 secs], 0.0074056 secs] [Times: user0.01 sys0.00, real0.01 secs]5、清除阶段 Cleanup phase 紧挨着重新标记阶段的清除(Clean)阶段该阶段是部分并发的。 清除阶段主要执行以下操作 RSet梳理启发式算法会根据活跃度和RSet尺寸对分区定义不同等级同时RSet数理也有助于发现无用的引用。参数-XX:PrintAdaptiveSizePolicy可以开启打印启发式算法决策细节整理堆分区为混合收集周期识别回收收益高(基于释放空间和暂停目标)的老年代分区集合识别所有空闲分区即发现无存活对象的分区。这类分区可在清除阶段直接回收无需等待下次收集周期。由于这样区域没有存活对象所以采用并发清空回收。 1.652: [GC cleanup 1213M-1213M(1885M), 0.0030492 secs] [Times: user0.01 sys0.00, real0.00 secs]如果需要回收一部分没有存活对象的区域则日志如下 1.872: [GC cleanup 1357M-173M(1996M), 0.0015664 secs] [Times: user0.01 sys0.00, real0.01 secs] 1.874: [GC concurrent-cleanup-start] 1.876: [GC concurrent-cleanup-end, 0.0014846 secs]注意 在标记过程的最后一个阶段清除阶段 Cleanup phase会直接对没有存活对象的分区进行回收无需等待下次收集周期。在初始标记阶段、重标记阶段、清理阶段会出现STW根区域扫描阶段和并发标记阶段都可以和应用程序并发执行不会出现STW。 作为对比CMS的老年代回收采用的是标记-清除算法其标记过程如下
初始标记CMS Initial Mark —— 标记GC root能直接关联的对象短暂STW并发标记CMS Concurrent Mark—— GCRootsTracing从并发标记中的root遍历对不可达的对象进行标记重新标记CMS Remark—— 修正并发标记期间因为用户操作导致标记发生表更的对象采用的incremental update算法会出现比较多的STW并发清除CMS Concurrent Sweep—— 由于是直接清理不涉及对象的复制转移所以阶段可以并发执行。 小结 CMS在整个过程中耗时最长的并发标记和并发清除过程中收集器线程都可以与用户线程一起工作不需要进行停顿只有初始标记和重新标记会出现STW。 这样看好像比G1老年代的标记-复制算法暂停时间更少因为G1的清理阶段也会出现STW暂停。其实不然 1、G1的初始标记阶段是在Young GC的STW过程中同步完成的。 3、重新标记阶段当堆内存太大时CMS重新标记的STW时间会逐渐不可控而G1的重新标记利用RSet采用的SATB算法STW时间非常短暂。 2、CMS会对老年代全区域进行回收而G1采用预测性算法对老年代Region的回收性价比排序每次都是在保证暂停时间可控的情况下回收性价比最高的内存Region所以单次回收的STW时间更加可控。 六、G1的垃圾回收 G1提供了两种GC模式Young GC和Mixed GC两种都是完全Stop The World的。
1、G1过程梳理 应用程序启动时会首先向服务器申请分配JVM内存并将申请到的内存划分为许多大小相同的区域Region这时的区域都是空闲状态 Free regions。当应用程序开始运行后会持续产生新的对象G1内存管理器会分配空闲Free regions作为年轻代的伊甸区eden regions存放这些新产生的对象。如果新产生的对象大于Region的一半则直接放入老年区的大对象区域Humongous Region。G1 GC为了匹配软实时soft real-time的目标会动态调整年轻代的大小当年轻代被填满后就会触发Young GCYoung GC会对整个年轻代和大对象区域Humongous Region进行回收。Young GC结束后依然存活的对象会被疏散evacuation到n(n1)个新的Survivor分区或者是老年代。当java heap占用达到 InitiatingHeapOccupancyPercent 定义的阈值之后在下一个Young GC开始的时候同时开始进行并发标记Concurrent Marking。并发标记Concurrent Marking和Young GC穿插执行在Concurrent Marking的过程中可能会出现多次Young-only GC。在并发标记Concurrent Marking的清理阶段会直接回收无存活对象的分区。当并发标记Concurrent Marking结束后会根据-XX:G1HeapWastePercent5设置的阈值判断是否需要执行Mixed GC。在Mixed GC阶段会对所有年轻代里的Region外加根据global concurrent marking统计得出收集收益高的若干老年代Region进行回收。如果Mixed GC实在无法跟上程序分配内存的速度导致老年代填满无法继续进行Mixed GC就会使用Serial old GCfull GC来收集整个java堆空间。注意G1本身并不提供full GC的。 G1中的垃圾回收主要分为2类Young GC和Mixed GC 说明 1、图中的圆圈表示G1回收过程中的暂停蓝色圆圈表示Young-only GC导致的暂停红色圆圈表示Mixed GC导致的暂停黄色圆圈表示有并发标记导致的暂停。 2、当java heap占用达到 InitiatingHeapOccupancyPercent 定义的阈值之后下一个Young-only GC收集将也会进行并发标记的初始标记如图中大蓝色圆圈。 3、Young-only GC和Concurrent Marking阶段可以穿插执行在Concurrent Marking的过程中可能会出现多次Young-only GC而Mixed GC只能在Concurrent Marking阶段完成后才能执行。 4、当完成并发标记阶段后不一定会立刻进行Mixed GC也可能会进行几次Young-only GC后才会进行Mixed GC。可能并没有达到G1HeapWastePercent设置的阈值 5、蓝色圆圈数量多于红色圆圈数量表示一般情况下Young-only GC发生的次数往往要大于Mixed GC的次数这也是G1努力使垃圾回收更加高效。 2、Young GC 年轻代垃圾回收阶段该阶段也被称为Young-only或Fully Young阶段会对整个年轻代的区域Region进行回收。 Eden区耗尽的时候就会触发新生代收集新生代垃圾收集会对整个新生代E S进行回收。 新生代垃圾收集期间整个应用STW新生代垃圾收集是由多线程并发执行的通过控制年轻代的region个数即年轻代内存大小来控制young GC的时间开销。新生代收集结束后依然存活的对象会被疏散evacuation到n(n1)个新的Survivor分区或者是老年代。该阶段会进行大对象区域的回收 Young GC日志示例 该次Young GC暂停过程中同时进行了大对象的分配并完成了并行标记的初始化标记。 2023-02-10T09:43:54.6630800: 10690912.762: [GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0274320 secs][Parallel Time: 21.8 ms, GC Workers: 4][GC Worker Start (ms): Min: 10690912762.4, Avg: 10690912762.4, Max: 10690912762.6, Diff: 0.2][Ext Root Scanning (ms): Min: 3.2, Avg: 3.5, Max: 3.7, Diff: 0.5, Sum: 14.1][Update RS (ms): Min: 16.6, Avg: 16.7, Max: 17.1, Diff: 0.5, Sum: 66.9][Processed Buffers: Min: 211, Avg: 216.8, Max: 225, Diff: 14, Sum: 867][Scan RS (ms): Min: 0.1, Avg: 0.3, Max: 0.5, Diff: 0.4, Sum: 1.4][Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][Object Copy (ms): Min: 0.5, Avg: 0.7, Max: 0.9, Diff: 0.4, Sum: 2.9][Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1][Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4][GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1][GC Worker Total (ms): Min: 21.3, Avg: 21.4, Max: 21.4, Diff: 0.1, Sum: 85.6][GC Worker End (ms): Min: 10690912783.8, Avg: 10690912783.8, Max: 10690912783.8, Diff: 0.0][Code Root Fixup: 0.0 ms][Code Root Purge: 0.0 ms][String Dedup Fixup: 2.4 ms, GC Workers: 4][Queue Fixup (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][Table Fixup (ms): Min: 2.1, Avg: 2.2, Max: 2.3, Diff: 0.3, Sum: 8.9][Clear CT: 0.3 ms][Other: 2.9 ms][Choose CSet: 0.0 ms][Ref Proc: 0.7 ms][Ref Enq: 0.0 ms][Redirty Cards: 0.1 ms][Humongous Register: 0.1 ms][Humongous Reclaim: 0.6 ms][Free CSet: 0.9 ms][Eden: 2170.0M(2454.0M)-0.0B(2452.0M) Survivors: 2048.0K-4096.0K Heap: 3693.3M(4096.0M)-946.1M(4096.0M)][Times: user0.10 sys0.00, real0.03 secs] 3、Mixed GC 混合垃圾回收阶段该阶段也被称为Space-reclamation阶段会选定所有年轻代里的Region外加根据global concurrent marking统计得出收集收益高的若干老年代Region进行回收。 整个阶段都是STW所有年轻代里的Region外加根据global concurrent marking统计得出收集收益高的若干老年代Region进行回收Mixed GC不是Full GC它只能回收部分老年代的Region如果Mixed GC实在无法跟上程序分配内存的速度导致老年代填满无法继续进行Mixed GC就会使用Serial old GCfull GC来收集整个GC heap。G1本身并不提供full GC的。该阶段会进行大对象区域的回收 2023-02-10T09:07:24.6610800: 10688722.759: [GC pause (G1 Evacuation Pause) (mixed), 0.0105385 secs][Parallel Time: 7.1 ms, GC Workers: 4][GC Worker Start (ms): Min: 10688722759.3, Avg: 10688722759.3, Max: 10688722759.4, Diff: 0.0][Ext Root Scanning (ms): Min: 1.6, Avg: 2.0, Max: 2.6, Diff: 1.1, Sum: 7.9][Update RS (ms): Min: 3.9, Avg: 4.4, Max: 4.6, Diff: 0.7, Sum: 17.4][Processed Buffers: Min: 48, Avg: 52.8, Max: 56, Diff: 8, Sum: 211][Scan RS (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.4][Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][Object Copy (ms): Min: 0.5, Avg: 0.6, Max: 0.7, Diff: 0.3, Sum: 2.3][Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4][GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][GC Worker Total (ms): Min: 7.0, Avg: 7.0, Max: 7.1, Diff: 0.0, Sum: 28.2][GC Worker End (ms): Min: 10688722766.4, Avg: 10688722766.4, Max: 10688722766.4, Diff: 0.0][Code Root Fixup: 0.0 ms][Code Root Purge: 0.0 ms][String Dedup Fixup: 2.3 ms, GC Workers: 4][Queue Fixup (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0][Table Fixup (ms): Min: 2.2, Avg: 2.2, Max: 2.2, Diff: 0.0, Sum: 8.8][Clear CT: 0.1 ms][Other: 1.0 ms][Choose CSet: 0.0 ms][Ref Proc: 0.3 ms][Ref Enq: 0.0 ms][Redirty Cards: 0.1 ms][Humongous Register: 0.1 ms][Humongous Reclaim: 0.1 ms][Free CSet: 0.2 ms][Eden: 204.0M(204.0M)-0.0B(2454.0M) Survivors: 0.0B-2048.0K Heap: 1255.0M(4096.0M)-944.2M(4096.0M)][Times: user0.04 sys0.00, real0.01 secs] 4、Full GC 作为一种兜底的备份策略如果mixed GC实在无法跟上程序分配内存的速度导致老年代填满无法继续进行Mixed GC就会使用serial old GCfull GC来收集整个GC heap。 整个过程都是STWG1并不提供full GC的这个Serial old GC提供的。Full gc是单线程的在Java 8中并且非常慢因此应避免在G1 GC的时候出现这个Full GC 不能觉得用了G1 GC收集器之后Java heap里面的GC不是Young GC 就Mixed GC还是存在Full GC。 G1 GC一旦发生了Full GC就说明当前程序的运行可能出现问题的需要考虑为什么会Full GC了 G1是如何满足目标暂停时间的 前提G1的JVM内存模型在物理上分区region、逻辑上分代 在年轻代收集Young GC期间G1 GC 调整年轻代(伊甸园和幸存者)的大小以来匹配软实时soft real-time的目标。在混合收集Mixed GC期间G1 GC 根据混合垃圾收集的目标数量、堆中每个区域中活动对象的百分比以及总体可接受的堆浪费百分比来调整收集的旧区域的数量以满足目标暂停时间目标。 七、参数介绍 参数说明-XX:UseG1GC使用 G1 收集器-XX:G1HeapRegionSizen设置 G1区域Region的大小。范围从1 MB 到32MB之间目标是根据最小的 Java 堆大小划分出大约2048个区域。-XX:MaxGCPauseMillis200设置最长暂停时间目标值默认是200毫秒-XX:G1NewSizePercent5设置年轻代最小值占总堆的百分比默认值是5%-XX:G1MaxNewSizePercent60设置年轻代最大值占总堆的百分比默认值是java堆的60%-XX:ParallelGCThreadsn设置STW并行工作的GC线程数一般推荐设置该值为逻辑处理器的数量最大是8如果逻辑处理器大于8则取逻辑处理器数量的5/8这适用于大多数情况除非是较大的SPARC系统其中的n值可以是逻辑处理器的5/16-XX:ConcGCThreadsn并发标记阶段并发执行的线程数一般n值为并行垃圾回收线程数ParallelGCThreads的1/4左右-XX:InitiatingHeapOccupancyPercent45设置触发全局并发标记周期的Java堆内存占用率阈值默认占用率阈值是整个Java堆的45%-XX:G1MixedGCLiveThresholdPercent85老年代Region中存活对象的占比只有当占比小于此参数的Old Region才会被选入CSet。这个值越大说明允许回收的Region中的存活对象越多可回收的空间就越少gc效果就越不明显-XX:G1HeapWastePercent5设置G1中愿意浪费的堆的百分比如果可回收region的占比小于该值G1不会启动Mixed GC默认值10%主要用来控制Mixed GC的触发时机。在global concurrent marking结束之后我们可以知道老年代regions中有多少空间要被回收在每次YGC之后和再次Mixed GC之前会检查垃圾占比是否达到此参数只有达到了下次才会触发Mixed GC。-XX:G1MixedGCCountTarget8一次全局并发标记后最多执行Mixed GC的次数次数越多单次回收的老年代的Region个数就越少暂停也就越短-XX:G1OldCSetRegionThresholdPercent10一次Mixed GC过程中老年代Region内存最多能被选入CSet中的占比-XX:G1ReservePercent10设置作为空闲空间的预留内存百分比用来降低目标空间溢出的风险默认是10%一般增加或减少百分比时需要确保也对java堆调整相同的量。 如何解锁VM经验值标志参数 在Java8中G1的众多参数中包含3个经验值参数如果需要调整经验值参数的值需要先解锁经验值标志。 3个经验值 -XX:G1NewSizePercent5 -XX:G1MaxNewSizePercent60 -XX:G1MixedGCLiveThresholdPercent85实例添加UnlockExperimentalVMOptions参数并调整参数G1NewSizePercent参数的经验值 java -XX:UnlockExperimentalVMOptions -XX:G1NewSizePercent10 -XX:G1MaxNewSizePercent75 G1test.jar注意事项 避免通过-Xmn 或其他相关选项(如-XX: NewRate)显式设置年轻代的大小因为年轻代的大小被固定后会导致G1的目标暂停机制失效。当设置目标暂停时间MaxGCPauseMillis时需要评估G1 GC 的延迟和应用程序吞吐量之间的取舍当该值设置较小时表明您愿意承担垃圾收集开销的增加从而会导致应用程序吞吐量的降低。Mixed GC的调优 1-XX:InitiatingHeapOccupancyPercent: 控制并发标记开始的内存占比阈值 2-XX:G1HeapWastePercent: 设置G1中愿意浪费的堆的百分比如果可回收region的占比小于该值G1不会启动Mixed GC默认值10%主要用来控制Mixed GC的触发时机。 3-XX:G1MixedGCLiveThresholdPercent设置老年代Region进入CSet的活跃对象占比阈值避免活跃对象占比过高的Region进入CSet 3-XX:G1MixedGCCountTarget and -XX:G1OldCSetRegionThresholdPercent: 主要是为了控制单次Mixed GC中Region的个数CSet中Region的个数越多GC过程中暂停时间越长。 八、典型问题 1、疏散失败Evacuation Failure 当没有更多的空闲region被提升到老一代或者复制到幸存空间时并且由于堆已经达到最大值堆不能扩展从而发生Evacuation Failure这时G1 的GC已经无能为力只能使用通过Serial old GC进行Full GC来收集整个java堆空间这个过程就是转移失败Evacuation Failure。 Young GC 疏散暂停Evacuation Pause过程出现内存耗尽的对应日志 注意G1 Evacuation Pause指的是G1垃圾回收过程中存活对象的复制-转移阶段被称为‘疏散暂停’阶段。 解决方案 如果有大量“空间耗尽to-space exhausted”或“空间溢出to-space overflow”GC事件则增加-XX:G1ReservePercent以增加“to-space”的预留内存量默认值是Java堆的10。注意G1 GC将此值限制在50以内。通过减少 -XX: InitiatingHeapOccupancyPercent 的值来更早地启动并发标记周期来及时回收不包含活跃对象的区域同时促使Mixed GC更快发生。增加选项-XX:ConcGCThreads的值以增加并行标记线程的数量减少并行标记阶段的耗时。 2、大对象分配Humongous Allocation Young GC过程中大对象分配时出现内存耗尽的对应日志 原因分析 出现大对象分配导致的内存耗尽问题一般是老年代剩余的Region中已经不能够找到一组连续的区域分配给新的巨型对象。 解决方案 通过-XX: G1HeapRegionSize 选项来增加内存区域Region的大小提升Region对象的判断标准以减少巨大对象的数量。增加堆java的大小使得有更多的空间来存放巨型对象通过-XX:G1MaxNewSizePercent降低年轻代Region的占比给老年代预留更多的空间从而给巨型对象提供给多的内存空间。 一般在疏散阶段Evacuation Pause和大对象分配Humongous Allocation会比较容易出现“空间耗尽to-space exhausted”或“空间溢出to-space overflow”的GC事件导致出现转移失败Evacuation Failure 进而引发Full GC 从而导致GC的暂停时间超过G1的设置的目标暂停时间。 所以我们要尽量避免出现转移失败Evacuation Failure。
3、Young GC花费时间太长 通常Young GC的耗时与年轻代的大小成正比具体地说是需要复制的集合集中的活跃对象的数量。 如果Young GC中CSet的疏散阶段Evacuate Collection Set phase需要很长时间尤其是其中的对象复制-转移可以通过降低-XX:G1NewSizePercent的值降低年轻代的最小尺寸从而降低停顿时间。 还可以使用-XX:G1MaxNewSizePercent降低年轻代的最大占比从而减少Young GC暂停期间需要处理的对象数量。 4、Mixed GC耗时太长 通过降低-XX:InitiatingHeapOccupancyPercent的值来调低并发标记阶段开始的阈值让并发标记阶段更早触发只有并发标记完成才能开始执行Mixed GC。通过调节-XX:G1MixedGCCountTarget 和 -XX:G1OldCSetRegionThresholdPercent参数降低单次回收的Region数量减少暂停时间。通过调节-XX:G1MixedGCLiveThresholdPercent的值避免活跃对象占比过高的Region进入CSet。因为活的对象越多region中可回收的空间就越少暂停时间就越长gc效果就越不明显。通过调节-XX:G1HeapWastePercent的值设置愿意浪费的堆的百分比。只有垃圾占比大于此参数才会发生Mixed GC该值越小会越早触发Mixed GC。 总结 本来主要对G1垃圾回收器的相关特性和实现机制做了详细介绍。 1、首先G1的内存模型进行了说明物理上分区逻辑上分代年轻代和老年代的区域不是连续的内存空间而是由分散的大小相同的内存块Region组成G1 GC会通过动态条件年轻代区域Region的数量以来匹配软实时soft real-time的目标。 2、详解介绍了G1 GC中的完整的垃圾回收流程以及Young GC、并发标记和Mixed GC的实现细节。 3、介绍了G1 GC的优缺点以及选用场景。 4、对G1的核心参数做了相关介绍并针对G1的重点问题提供了参数优化建议。