9.1 相关参数

通过阅读GC日志,我们可以了解Java虚拟机内存分配与回收策略。
内存分配与垃圾回收的参数列表
-XX:+PrintGC 输出GC日志。类似: -verbose: gc
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX;+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如2013-05-04T21:53:59.234+0800)
-Xx:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-xloggc: . ./ logs/gc.log 日志文件的输出路径
例子:
image.png
image.png
image.png
image.png
image.png
如果想把GC日志存到文件的话,是下面这个参数: -Xloggc: /path/to/gc.log
日志补充说明:

  • “[GC”和”[Full GC”说明了这次垃圾收集的停顿类型,如果有”Full”则说明GC发生了”StopThe World”
  • 使用Serial收集器在新生代的名字是Default New Generation,因此显示的是”[DefNew”
  • 使用ParNew收集器在新生代的名字会变成” [ ParNew”,意思是”Parallel New Generation”
  • 使用Parallel Scavenge收集器在新生代的名字是”[ PSYoungGen”
  • 老年代的收集和新生代道理一样,名字也是收集器决定的
  • 使用G1收集器的话,会显示为”garbage-first heap”
  • Allocation Failure

表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。

  • [PSYoungGen:5986K->696K(8704K) ]5986K->704K(9216K)

中括号内:GC回收前年轻代大小,回收后大小,(年轻代总大小)
括号外:GC回收前年轻代和老年代大小,回收后大小,(年轻代和老年代总大小)
image.png

  • user代表用户态回收耗时,sys内核态回收耗时,rea实际耗时。由于多核的原因,时间总和可能会超过real时间
  • image.png

image.png
Young GC
image.png
Full GC
image.png

9.2 例子

通过例子解读堆空间情况,-verbose:gc是输出简单信息的参数,一般都是使用详细信息参数-XX:+PrintGCDetails
image.png
JDK7的输出
image.png
JDK8的输出
image.png
前三个2兆对象放到新生代后,在放入4兆的对象时,触发了GC,JVM将三个2兆的对象放入了老年代,将4兆的对象放入了新生代,因为三个2兆的对象无法放入from和to区,所以直接放入了老年代,那些0x00000000f9a00000是内存分配的地址值,JDK8是直接将4兆的对象放入老年代
image.png
image.png

  • 如果想把GC日志存到文件的话,是下面这个参数:-Xloggc:/path/to/gc.log

例如:-Xloggc:./logs/gc.log 其中 .是代表当前项目目录
可以用一些工具去分析这些gc日志。
常用的日志分析工具有:GCViewer、GCEasy、GCHisto、GCLogviewer,Hpjmeter、garbagecat等。GCEasy是款在线分析工具,推荐使用

10. 垃圾回收器的新发展

10.1 概述

GC仍然处于飞速发展之中,目前的默认选项G1 GC在不断的进行改进,很多我们原来认为的缺点,例如串行的Full GC、Card Table扫描的低效等,都已经被大幅改进,例如,JDK 10以后,Full GC已经是并行运行,在很多场景下,其表现还略优于Parallel GC的并行Full GC实现。
即使是Serial GC,虽然比较古老,但是简单的设计和实现未必就是过时的,它本身的开销,不管是GC相关数据结构的开销,还是线程的开销,都是非常小的所以随着云计算的兴起,在Serverless等新的应用场景下,Serial GC找到了新的舞台。
比较不幸的是CMS GC,因为其算法的理论缺陷等原因,虽然现在还有非常大的用户群体,但在JDK9中已经被标记为废弃,并在JDK14版本中移除。

10.2 JDK11新特性

image.png

10.3 Open JDK12的Shenandoah GC

  • 现在G1回收器已成为默认回收器好几年了。
  • 我们还看到了引入了两个新的收集器:ZGC(JDK11出现)和shenandoah(open JDK12)。

√ 主打特点:低停顿时间

  • Open JDK12的shenandoah GC:低停顿时间的GC(实验性)
  • Shenandoah,无疑是众多GC中最孤独的一个。是第一款不由oracle公司团队领导开发的HotSpot垃圾收集器。不可避免的受到官方的排挤。比如号称openJDK和OracleDK没有区别的Oracle公司仍拒绝在oracleJDK12中支持Shenandoah。
  • Shenandoah垃圾回收器最初由RedHat进行的一项垃圾收集器研究项目PauselessGc的实现,旨在针对JVM上的内存回收实现低停顿的需求。在2014年贡献给openJDK。
  • Red Hat研发shenandoah团队对外宣称,Shenandoah垃圾回收器的暂停时间与堆大小无关,这意味着无论将堆设置为200 MNB还是200GB,99.9%的目杯都可以把垃圾收集的停顿时间限制在十毫秒以内。不过实际使用性能将取决于实际工作堆的大小和工作负载。

image.png
image.png

10.4 革命性的ZGC: JDK14新特性

https : //docs.oracle.com/en/java/javase/12/gctuning/
image.png

  • ZGC与shenandoah目标高度相似,在尽可能对吞吐量影响不大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。
  • 《深入理解Java虚拟机》一书中这样定义ZGC: ZGC收集器是一款基于Region内存布局的,(暂时)不设分代的,使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-压缩算法的,以低延迟为首要目标的一款垃圾收集器。
  • ZGC的工作过程可以分为4个阶段:并发标记-并发预备重分配-并发重分配-并发重映射等。
  • ZGC几乎在所有地方并发执行的,除了初始标记的是STW的。所以停顿时间几乎就耗费在初始标记上,这部分的实际时间是非常少的。

image.png
image.png
在ZGC的强项停顿时间测试上,它毫不留情的将Parallel、G1拉开了两个数量级的差距。无论平均停顿、95%停顿、99%停顿、99.9%停顿,还是最大停顿时间,ZGC都能毫不费劲控制在10毫秒以内。
image.png
JEP 364: ZGC应用在macos上JEP
365:ZGC应用在windows上

  • JDK14之前,ZGC仅Linux才支持。
  • 尽管许多使用ZGC的用户都使用类Linux的环境,但在windows和macOS上,人们也需要ZGC进行开发部署和测试。许多桌面应用也可以从ZGC中受益。因此,ZGC特性被移植到了windows和macOS上。
  • 现在mac或windows上也能使用ZGC了,示例如下:

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC