G1垃圾回收器停顿时间长排查 |
您所在的位置:网站首页 › 排查时间 › G1垃圾回收器停顿时间长排查 |
-XX:+UseG1GC -Xloggc:log/gc.log.$(date +%Y-%m-%d-%H-%M) -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCDetails 这篇文章将深入研究G1的日志和调优参数。为了在实际工作中对G1进行调优,作为开发者的你需要理解G1垃圾收集器的每个步骤,以及每个步骤在整个垃圾收集周期中的作用。为了方便读者学习,这篇文章将G1的日志参数分为等级递增的三块,这篇文章将会分别介绍每一部分参数的作用和调优时候使用的场景。 基础参数 - 在生产中使用G1收集器,必须使用这些参数高级参数 - 随着应用的成熟或业务负载的增加,需要使用这些参数针对某些问题进行调优。Debug参数 - 这些参数是用来解决特定的性能问题,如果某个问题在非生产环境中无法复现,才会在生产环境中使用这些参数排查问题。 基础参数如果你要在生产环境中使用G1 GC,下面这些跟日志相关的参数是必备的,有了这些参数,你才能排查基本的垃圾回收问题。 使用-XX:GCLogFileSize设置合适的GC日志文件大小,使用-XX:NumberOfGCLogFiles设置要保留的GC日志文件个数,使用-Xloggc:/path/to/gc.log设置GC日志文件的位置,通过上面三个参数保留应用在运行过程中的GC日志信息,我建议最少保留一个星期的GC日志,这样应用的运行时信息足够多的,方便排查问题。 新生代收集和其他垃圾收集器一样,G1也使用-XX:PrintGCDetails打印出详细的垃圾收集日志,下面这张图是新生代收集的标准流程,我在这里将它分成了6个步骤: G1的第二种收集活动是并发垃圾收集,并发垃圾收集的触发条件有很多,但是做的工作都相同,它的日志如下图所示: 标志着并发垃圾收集阶段的开始: GC pause(G1 Evacuation Pause)(young)(initial-mark):为了充分利用STW的机会来trace所有可达(存活)的对象,initial-mark阶段是作为新生代垃圾收集中的一部分存在的(搭便车)。initial-mark设置了两个TAMS(top-at-mark-start)变量,用来区分存活的对象和在并发标记阶段新分配的对象。在TAMS之前的所有对象,在当前周期内都会被视作存活的。表示第并发标记阶段做的第一个事情:根分区扫描 GC concurrent-root-region-scan-start:根分区扫描开始,根分区扫描主要扫描的是新的survivor分区,找到这些分区内的对象指向当前分区的引用,如果发现有引用,则做个记录;GC concurrent-root-region-scan-end:根分区扫描结束,耗时0.0030613s表示并发标记阶段 GC Concurrent-mark-start:并发标记阶段开始。(1)并发标记阶段的线程是跟应用线程一起运行的,不会STW,所以称为并发;并发标记阶段的垃圾收集线程,默认值是Parallel Thread个数的25%,这个值也可以用参数-XX:ConcGCThreads设置;(2)trace整个堆,并使用位图标记所有存活的对象,因为在top TAMS之前的对象是隐式存活的,所以这里只需要标记出那些在top TAMS之后、阈值之前的;(3)记录在并发标记阶段的变更,G1这里使用了SATB算法,该算法要求在垃圾收集开始的时候给堆做一个快照,在垃圾收集过程中这个快照是不变的,但实际上肯定有些对象的引用会发生变化,这时候G1使用了pre-write barrier记录这种变更,并将这个记录存放在一个SATB缓冲区中,如果该缓冲区满了就会将它加入到一个全局的缓冲区,同时G1有一个线程在并行得处理这个全局缓冲区;(4)在并发标记过程中,会记录每个分区的存活对象占整个分区的大小的比率;GC Concurrent-mark-end:并发标记阶段结束,耗时0.3055438s重新标记阶段,会Stop the World Finalize Marking:Finalizer列表里的Finalizer对象处理,耗时0.0014099s;GC ref-proc:引用(soft、weak、final、phantom、JNI等等)处理,耗时0.0000480s;Unloading:类卸载,耗时0.0025840s;除了前面这几个事情,这个阶段最关键的结果是:绘制出当前并发周期中整个堆的最后面貌,剩余的SATB缓冲区会在这里被处理,所有存活的对象都会被标记;清理阶段,也会Stop the World 计算出最后存活的对象:标记出initial-mark阶段后分配的对象;标记出至少有一个存活对象的分区;为下一个并发标记阶段做准备,previous和next位图会被清理;没有存活对象的老年代分区和巨型对象分区会被释放和清理;处理没有任何存活对象的分区的RSet;所有的老年代分区会按照自己的存活率(存活对象占整个分区大小的比例)进行排序,为后面的CSet选择过程做准备;并发清理阶段 GC concurrent-cleanup-start:并发清理阶段启动。完成第5步剩余的清理工作;将完全清理好的分区加入到二级free列表,等待最终还会到总体的free列表;GC concurrent-cleanup-end:并发清理阶段结束,耗时0.0012954s 混合收集在并发收集阶段结束后,你会看到混合收集阶段的日志,如下图所示,该日志的大部分跟之前讨论的新生代收集相同,只有第1部分不一样:GC pause(G1 Evacuation Pause)(mixed),0.0129474s,这一行表示这是一个混合垃圾收集周期;在混合垃圾收集处理的CSet不仅包括新生代的分区,还包括老年代分区——也就是并发标记阶段标记出来的那些老年代分区。 如果堆内存空间不足以分配新的对象,或者是Metasapce空间使用率达到了设定的阈值,那么就会触发Full GC——你在使用G1的时候应该尽量避免这种情况发生,因为G1的Full Gc是单线程、会Stop The World,代价非常高。Full GC的日志如下图所示,从中你可以看出三类信息 Full GC的原因,这个图里是Allocation Failure,还有一个常见的原因是Metadata GC Threshold;Full GC发生的频率,每隔几天发生一次Full GC还可以接受,但是每隔1小时发生一次Full GC则不可接受;Full GC的耗时,这张图里的Full GC耗时150ms(PS:按照我的经验,实际运行中如果发生Full GC,耗时会比这个多很多)基础配置参数中,我这里还想介绍两个:-XX:+PrintGCApplicationStoppedTime和-XX:+PrintGCApplicationConcurrentTime,这两个参数也可以为你提供有用的信息,如下图所示: |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |