前言
生产系统中,Serial其实几乎不用了;
现在来说,HotSpot的ZGC还不成熟,目前最好用的GC就是G1了
JDK8开始支持G1
保守一些的企业,可能用的是JDK7,这时候其实响应时间优先,也就是用PS + PO了;
CMS一旦SerialOld时,会STW很久,所以没啥必要用它,还会带来很多麻烦(CMS帮G1和ZGC踩了很多坑)
如果用了JDK8,那么就建议使用G1
CMS的问题
Memory Fragmentation(内存碎片化)
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction 默认为0 指的是经过多少次FGC才进行压缩
Floating Garbage(浮动垃圾)
Concurrent Mode Failure
产生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
解决方案:降低触发CMS的阈值
PromotionFailed
解决方案类似,保持老年代有足够的空间
–XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,让CMS保持老年代足够的空间
CMS的日志格式
执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.mashibing.jvm.gc.T15_FullGC_Problem01
结果如下:
[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
ParNew:年轻代收集器
6144->640:收集前后的对比
(6144):整个年轻代容量
6585 -> 2770:整个堆的情况
(19840):整个堆大小
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs]
[Times: user=0.01 sys=0.00, real=0.00 secs]
//8511 (13696) : 老年代使用(最大)
//9866 (19840) : 整个堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
//这里的时间意义不大,因为是并发执行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//标记Card为Dirty,也称为Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)]
[Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs]
[scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs]
[1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//STW阶段,YG occupancy:年轻代占用及容量
//[Rescan (parallel):STW下的存活对象标记
//weak refs processing: 弱引用处理
//class unloading: 卸载用不到的class
//scrub symbol(string) table:
//cleaning up symbol and string tables which hold class-level metadata and
//internalized string respectively
//CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
//10108K(19840K): 阶段过后的堆占用及容量
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
//标记已经完成,进行并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//重置内部结构,为下次GC做准备
G1的日志格式
Garbage First Garbage Collector Tuning
如果你生产是 1.8 的 jdk,你就可以用 G1 了。推荐你使用。
G1是把堆内存从逻辑上划分成很多个小块(Region)
G1以前,PS,CMS等,都会设置一个Xmn年轻代大小;
但是G1不推荐指定年轻代大小,因为G1会自动调整它(根据YGC时间和设定的停顿时间)
G1的几个回收阶段:
- YGC(STW)
- MixedGC,很像CMS的四个阶段
- FGC(SerialOld)
G1的调优目标就是尽量避免FGC
执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseG1GC com.mashibing.jvm.gc.T15_FullGC_Problem01
[GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
//young -> 年轻代 , Evacuation-> 复制存活对象
//initial-mark 混合回收的阶段,这里是YGC混合老年代回收
[Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
[GC Worker Start (ms): 92635.7]
[Ext Root Scanning (ms): 1.1]
[Update RS (ms): 0.0]
[Processed Buffers: 1]
[Scan RS (ms): 0.0]
[Code Root Scanning (ms): 0.0]
[Object Copy (ms): 0.1]
[Termination (ms): 0.0]
[Termination Attempts: 1]
[GC Worker Other (ms): 0.0]
[GC Worker Total (ms): 1.2]
[GC Worker End (ms): 92636.9]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.0 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
[Times: user=0.00 sys=0.00, real=0.00 secs]
//以下是混合回收其他阶段
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000078 secs]
[GC concurrent-mark-start]
//无法evacuation,进行FGC
[Full GC (Allocation Failure) 18M->18M(20M), 0.0719656 secs]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]
GC常用参数
GC通用参数
-
-Xmn -Xms -Xmx -Xss
年轻代 最小堆 最大堆 栈空间 -
-XX:+PrintFlagsInitial
JVM各参数的默认值 -
-XX:+UseTLAB
使用TLAB,默认打开,建议别动 -
-XX:+PrintTLAB
打印TLAB的使用情况 -
-XX:TLABSize
设置TLAB大小,建议别动 -
-XX:+DisableExplictGC
让 System.gc()不管用 ,一般会打开
System.gc()方法是程序建议JVM进行FGC -
-XX:+PrintGC
打印GC日志 -
-XX:+PrintGCDetails
打印GC详情日志 -
-XX:+PrintHeapAtGC
GC时打印堆栈情况 -
-XX:+PrintGCTimeStamps
GC时打印系统时间 -
-XX:+PrintGCApplicationConcurrentTime (低)
打印应用程序时间 -
-XX:+PrintGCApplicationStoppedTime (低)
打印暂停时长 -
-XX:+PrintReferenceGC (重要性低)
记录回收了多少种不同引用类型的引用 -
-verbose:class
类加载详细过程 -
-XX:+PrintVMOptions
打印JVM运行时的参数 -
-XX:+PrintFlagsFinal
JVM各参数的最终值
相当于JVM参数字典表
必须会用 -
-Xloggc:opt/log/gc.log
记录GC日志 -
-XX:MaxTenuringThreshold
升代年龄,最大值15(CMS默认6,其他默认15) -
锁自旋次数 -XX:PreBlockSpin; 热点代码检测参数-XX:CompileThreshold; 逃逸分析 标量替换 …
这些不建议设置
Parallel常用参数
-
-XX:SurvivorRatio
Eden : S0 : S1 默认比例是 8 : 1 : 1 -
-XX:PreTenureSizeThreshold
大对象到底多大,会被直接分配到old区 -
-XX:MaxTenuringThreshold 升代年龄
-
-XX:+ParallelGCThreads
并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同 -
-XX:+UseAdaptiveSizePolicy
自动选择各区大小比例
CMS常用参数
-
-XX:+UseConcMarkSweepGC
-
-XX:ParallelCMSThreads
CMS线程数量,CMS只是Old区的GC,所以要留一些资源给其他人 -
-XX:CMSInitiatingOccupancyFraction
使用多少比例的老年代后开始CMS收集,默认是68%(近似值),
如果频繁发生SerialOld卡顿,应该调小,(CMS回收更加频繁) -
-XX:+UseCMSCompactAtFullCollection
在FGC时进行压缩(CMS默认不压缩,只是Sweep;压缩会时GC时间增加)
解决FGC碎片化 -
-XX:CMSFullGCsBeforeCompaction
多少次FGC之后进行压缩
解决FGC碎片化 -
-XX:+CMSClassUnloadingEnabled
回收方法区的Class -
-XX:CMSInitiatingPermOccupancyFraction
达到什么比例时进行Perm回收(JDK<=1.7时,方法区由永久代实现) -
GCTimeRatio
设置GC时间占用程序运行时间的百分比,是个建议 -
-XX:MaxGCPauseMillis
停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代
G1常用参数
-
-XX:+UseG1GC
-
-XX:MaxGCPauseMillis
停顿时间,建议值,G1会尝试调整Young区的块数来达到这个值 -
-XX:GCPauseIntervalMillis
?GC的停顿间隔时间 -
-XX:+G1HeapRegionSize
分区大小,建议逐渐增大该值,1 2 4 8 16 32。
随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长
ZGC做了改进(动态区块大小) -
G1NewSizePercent
新生代最小比例,默认为5% -
G1MaxNewSizePercent
新生代最大比例,默认为60%
G1会动态调整新生代大小 -
GCTimeRatio
GC时间建议比例,G1会根据这个值调整堆空间 -
ConcGCThreads
线程数量 -
InitiatingHeapOccupancyPercent
启动G1的堆空间占用比例
纤程(协程)
自己搜资料了解一下