编程语言
首页 > 编程语言> > java垃圾回收及gc全面解析(全面覆盖cms、g1、zgc、openj9)

java垃圾回收及gc全面解析(全面覆盖cms、g1、zgc、openj9)

作者:互联网

  一般来说,gc的停顿时间和活跃对象的堆大小成比例,视gc线程的数量,每1GB可能会停顿1-3秒,且cpu数量通常和gc呈现阿姆达尔定律(Amdahl’s Law),而非我们直观计算的线性变化。如下:

  

   体现在gc中的时候,不同cpu数量下的gc成本如下:

  

  使用不同类型的gc将会在停顿和吞吐量之间发生很大的变化(一般都是基于这两个目标之一),不恰当的设置gc甚至可能会导致OOM,但是无论如何都不会存在一个最好的gc,就如linux的cpu调度算法一样,不同的负载类型下都有最好的gc,但是没有打遍天下无敌手的招式。包括azul引以为傲的C4(采用连续性并发压缩实现,完全无STW)也一样,停顿几乎消失了,但是吞吐量降下来了。如下:

  

  

 

  和gc相关的核心定义包括:

  GC的步骤。总体来说,gc的过程分为下列几步:

  

   

  由于在标记过程中,引用关系是会变的,主要是原来不引用的、现在引用了,所以gc一般采用写屏障来跟踪这些变化。

  不同的垃圾回收器会采用不同方式实现,有的完全分三步,有的合并某些部分。不同的实现会导致不同的后果,包括gc占用的额外内存大小、速度、堆碎片、gc速度等等。

何时发生GC

  1、eden区不够,且对象不直接在old区分配,则虚拟机发起Minor GC。

  2、old区超过给定阈值(由参数InitiatingHeapOccupancyPercent控制,默认为45%,可配置)或担保分配失败,虚拟机发起Full GC。

核心参数

  命令java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version可以打印所有jvm参数默认值,也可以启动时带上。有好几百个选项,比oracle优化器提示以及银行参数还多。

  -XX:MaxGCPauseMillis=<nnn>:提示优化器应努力达到的最大暂停时间,gc会据此调整堆栈大小以及gc频率、其它参数,但是它和数据库优化器提示一样,只是尽力遵守。

  -XX:GCTimeRatio=nnn:提示优化器应努力达到的最大gc时间占比。公式为1/ (1+nnn)。设置为19代表最多5%用于gc。如果该时间无法达到,gc会考虑加大堆大小(默认初始:1/64物理内存,最大1/4物理内存)。

  -XX:UseAdapativeSizePolicy。让gc自动根据上面两个参数的大小动态调整新生代(eden、survivor)、老年代的大小。

  -XX:+UseTLAB:是否启用线程本地分配缓冲(类似oracle的private redo buffer),能够降低分配锁争用。

  -XX:PretenureSizeThreshold:超过多大的对象直接的old区分配,默认为0,首先在eden区分配。这个就得看情况了,一般来说大对象不应该朝生暮死,但是有些批处理系统就比较复杂了,设置该值的仔细测试,就OLTP而言,该值应该设置。

  -XX:NewRatio=2:老生代/新年代默认比例。

  -XX:NewSize=2m:新年代默认大小。

  -XX:MaxNewSize=2m:新年代最大大小。

  如果堆已经是最大大小,但是吞吐量未达到,说明堆最大值太小,比如默认值;如果吞吐量达到了,但是暂停太长,可以设置最大暂停时间。但是它俩通常无法同时100%满足,需要取舍(当然如果系统负载很低,通常都能达到。所以重点是负载高的时候)。

  影响gc的核心因素是堆大小以及年轻代的比例。

  默认情况下,如果服务器线程数小于8,则gc线程数量为8;如果大于8,则为5/8(在某些特殊环境中,则为5/16)。当使用多个gc线程时,堆会产生一些碎片,因为每个gc线程都会都老年代划一部分空间用于临时存储从年轻代移动到老年代的对象(此举是为了降低堆分配的竞争),gc线程数越少、意味着碎片也越少。

主流GC

  

 

   其中初始标记和重新标记速度一般非常快,并发标记则慢得多。因为GC过程中用户线程仍然运行,所以CMS的一个缺点是有些不再使用的对象会遗留到下一次才会被回收。当然还有一些和老年代碎片相关的问题也需要注意,在jdk 8u100+之后,g1应该来说要比cms合适了,这里就不细讲了,有兴趣可以一个个参数研究一下。

  

  捐献给eclispse基金会后,现在的openj9还可以使用hotspot jvm,意味着可以使用open jdk的gc如zgc。

典型的gc优化策略

GC日志的详细分析

  不同JVM的gc日志差异比较大,这里主要分析CMS、G1、zgc以及openj9 zgc的日志。不同的gc日志选项输出的日志内容差异也比较大,详见gc日志输出深入解析-覆盖CMS、并行GC、G1、ZGC、openj9

相关参考资料

 

标签:线程,java,g1,XX,STW,GC,内存,gc,zgc
来源: https://www.cnblogs.com/zhjh256/p/11877069.html