前言
生产系统中,Serial其实几乎不用了;
现在来说,HotSpot的ZGC还不成熟,目前最好用的GC就是G1了
JDK8开始支持G1
保守一些的企业,可能用的是JDK7,这时候其实响应时间优先,也就是用PS + PO了;
CMS一旦SerialOld时,会STW很久,所以没啥必要用它,还会带来很多麻烦(CMS帮G1和ZGC踩了很多坑)
如果用了JDK8,那么就建议使用G1
CMS和G1的GC日志分析解读
CMS日志分析
CMS分为四个大阶段: 初始标记(STW),并发标记,重新标记(STW),并发回收
但其实并发标记之后,紧接着还有个concurrent-preclean,标记Card为Dirty,也称为Card Marking
并发回收之后,紧接着还有个concurrent-reset,重置内部结构,为下次GC做准备
执行命令: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
▪https://www.oracle.com/technical-resources/articles/java/g1gc.html
G1是把堆内存从逻辑上划分成很多个小块(Region)
G1以前,PS,CMS等,都会设置一个Xmn年轻代大小;
但是G1不推荐指定年轻代大小,因为G1会自动调整它(根据YGC时间,和设定的停顿时间)
G1的几个回收阶段:
- YGC(STW)
- MixedGC,很像CMS的四个阶段
FGC(SerialOld)
G1的调优目标就是尽量避免FGC<br />执行命令: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:+PrintFlagsFinal
JVM各参数的最终值
相当于JVM参数字典表
-XX:+PrintFlagsInitial
JVM各参数的默认值
-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运行时的参数
-Xloggc:opt/log/gc.log
记录GC日志
-XX:MaxTenuringThreshold
升代年龄,最大值15(CMS默认6,其他默认15)
锁自旋次数 -XX:PreBlockSpin; 热点代码检测参数-XX:CompileThreshold; 逃逸分析 标量替换 …
这些不建议设置
-XX:+UseTLAB
使用TLAB,默认打开,建议别动
-XX:+PrintTLAB
打印TLAB的使用情况
-XX:TLABSize
设置TLAB大小,建议别动
Parallel常用参数
-XX:+UseParallelGC
-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时间增加)
-XX:CMSFullGCsBeforeCompaction
多少次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的堆空间占用比例
JVM总结:
class file format
class loader,双亲委派,loading,linking,initializing
JMM,CPU乱序执行,如何保证不乱序,volatile,synchronized
对象的大小
JVM分代模型,各个垃圾回收器,回收算法,JVM调优