前言

生产系统中,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]

  1. ParNew:年轻代收集器
  2. 6144->640:收集前后的对比
  3. 6144):整个年轻代容量
  4. 6585 -> 2770:整个堆的情况
  5. 19840):整个堆大小
  1. [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]
  2. //8511 (13696) : 老年代使用(最大)
  3. //9866 (19840) : 整个堆使用(最大)
  4. [CMS-concurrent-mark-start]
  5. [CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
  6. //这里的时间意义不大,因为是并发执行
  7. [CMS-concurrent-preclean-start]
  8. [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
  9. //标记Card为Dirty,也称为Card Marking
  10. [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]
  11. //STW阶段,YG occupancy:年轻代占用及容量
  12. //[Rescan (parallel):STW下的存活对象标记
  13. //weak refs processing: 弱引用处理
  14. //class unloading: 卸载用不到的class
  15. //scrub symbol(string) table:
  16. //cleaning up symbol and string tables which hold class-level metadata and
  17. //internalized string respectively
  18. //CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
  19. //10108K(19840K): 阶段过后的堆占用及容量
  20. [CMS-concurrent-sweep-start]
  21. [CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
  22. //标记已经完成,进行并发清理
  23. [CMS-concurrent-reset-start]
  24. [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
  25. //重置内部结构,为下次GC做准备

G1

https://www.oracle.com/technical-resources/articles/java/g1gc.html

G1是把堆内存从逻辑上划分成很多个小块(Region)
G1以前,PS,CMS等,都会设置一个Xmn年轻代大小;
但是G1不推荐指定年轻代大小,因为G1会自动调整它(根据YGC时间,和设定的停顿时间)

G1的几个回收阶段:

  1. YGC(STW)
  2. MixedGC,很像CMS的四个阶段
  3. FGC(SerialOld)

    1. G1的调优目标就是尽量避免FGC<br />执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseG1GC com.mashibing.jvm.gc.T15_FullGC_Problem01
    1. [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
    2. //young -> 年轻代 Evacuation-> 复制存活对象
    3. //initial-mark 混合回收的阶段,这里是YGC混合老年代回收
    4. [Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
    5. [GC Worker Start (ms): 92635.7]
    6. [Ext Root Scanning (ms): 1.1]
    7. [Update RS (ms): 0.0]
    8. [Processed Buffers: 1]
    9. [Scan RS (ms): 0.0]
    10. [Code Root Scanning (ms): 0.0]
    11. [Object Copy (ms): 0.1]
    12. [Termination (ms): 0.0]
    13. [Termination Attempts: 1]
    14. [GC Worker Other (ms): 0.0]
    15. [GC Worker Total (ms): 1.2]
    16. [GC Worker End (ms): 92636.9]
    17. [Code Root Fixup: 0.0 ms]
    18. [Code Root Purge: 0.0 ms]
    19. [Clear CT: 0.0 ms]
    20. [Other: 0.1 ms]
    21. [Choose CSet: 0.0 ms]
    22. [Ref Proc: 0.0 ms]
    23. [Ref Enq: 0.0 ms]
    24. [Redirty Cards: 0.0 ms]
    25. [Humongous Register: 0.0 ms]
    26. [Humongous Reclaim: 0.0 ms]
    27. [Free CSet: 0.0 ms]
    28. [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
    29. [Times: user=0.00 sys=0.00, real=0.00 secs]
    30. //以下是混合回收其他阶段
    31. [GC concurrent-root-region-scan-start]
    32. [GC concurrent-root-region-scan-end, 0.0000078 secs]
    33. [GC concurrent-mark-start]
    34. //无法evacuation,进行FGC
    35. [Full GC (Allocation Failure) 18M->18M(20M), 0.0719656 secs]
    36. [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
    37. 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调优