GC(Allocation Failure)引发的JVM知识回顾

最近项目有些不稳定,偶发性的出现GC overhead limit异常,需要经常性的查看GC日志以及JVM虚拟机监测。
所以借此机会复习一下JVM的相关知识,毕竟我们要时常进行总结,颗粒归仓。

先来看一下GC日志的部分截图

在这里插入图片描述
以下部分是Java虚拟机的一些信息,

Java HotSpot(TM) 64-Bit Server VM (25.171-b11) for linux-amd64 JRE (1.8.0_171-b11), built on Mar 28 2018 17:07:08 by "java_re" with gcc 4.3.0 20080428 (Red Hat 4.3.0-8)
Memory: 4k page, physical 16251612k(176016k free), swap 4194300k(186268k free)
CommandLine flags: -XX:InitialHeapSize=2147483648 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC

我们首先关注一下日志中的一些重要的参数


-XX:InitialHeapSize=2147483648 //设置Java程序初始堆内存的大小
-XX:MaxHeapSize=2147483648 // 设置Java程序最大堆内存的大小

// 设置参数时默认的单位是byte,我们也可以使用m,g等单位来进行转换这样看起来比较方便
-XX:InitialHeapSize=2g //设置Java程序初始堆内存的大小
-XX:MaxHeapSize=2g // 设置Java程序最大堆内存的大小

在实际使用过程中,初始化堆内存的大小通常被视为堆内存大小的下界。然而JVM可以在运行时动态的调整堆内存的大小,所以理论上来说我们有可能会看到堆内存的大小小于初始化堆内存的大小。但是即使在非常低的堆内存使用下,我也从来没有遇到过这种情况。这种行为将会方便开发者和系统管理员,因为我们可以通过将这两个参数设置为相同大小来获得一个固定大小的堆内存。

-XX:InitialHeapSize和-XX:MaxHeapSize 实际上也可以用缩写来代替,这两个缩写我们一定非常熟悉 -Xms和-Xmx。我们也可以直接使用这两个参数,它们所起得效果是一样的。


以下参数比较简单,就不再过多说明

-XX:+PrintGC //输出GC日志
-XX:+PrintGCDateStamps //输出GC的时间戳(以日期的形式,如 2021-05-04T21:53:59.234+0800
-XX:+PrintGCDetails //输出GC的详细日志
-XX:+PrintGCTimeStamps //输出GC的时间戳(以基准时间的形式)

-XX:+UseCompressedOops //普通对象指针压缩
-XX:+UseCompressedClassPointers //类指针压缩

首先了解一下这两个参数是干什么的

指针压缩 (64位平台上默认打开)
1、使用-XX:+UseCompressedOops压缩对象指针
2、使用-XX:+UseCompressedClassPointers选项来压缩类指针,对象中指向类元数据的指针会被压缩成32位

举个例子

//new一个对象
Object o=new Object()

如果不开启普通对象指针压缩,-UseCompressedOops,会在内存中消耗24个字节,o 指针占8个字节,Object对象占16个字节。
如果开启普通对象指针压缩,+UseCompressedOops,会在内存中消耗20个字节,o指针占4个字节,Object对象占16个字节。
开启UseCompressedOops,默认会开启UseCompressedClassPointers,而且开启UseCompressedClassPointers依赖于+UseCompressedOops。
如果开启类指针压缩,+UseCompressedClassPointers,根据上面的条件,结果跟只开启UseCompressedOops一样,会在内存中消耗20个字节,o指针占4个字节,Object对象占16个字节。


在复习下面参数时,我们回顾一下Java中GC的类型

参数描述
UseSerialGC虚拟机运行在Client模式的默认值,打开此开关参数后,使用Serial+Serial Old收集器组合进行垃圾收集
UseParNewGC使用此参数后,使用ParNew+Serial Old收集器组合进行垃圾收集
UseConcMarkSweepGC使用此参数后,使用ParNew+CMS+Serial Old 收集器组合进行垃圾收集。Serial Old作为CMS收集器出现Concurrent Mode Failure的备用垃圾收集器
UseParallelGC虚拟机运行在Server模式的默认值,使用此参数后,使用ParallelScavenge+Serial Old收集器组合进行垃圾收集
UseParallelOldGC使用此参数后,使用Parallel Scavenge+Parallel Old收集器组合进行垃圾收集。
-XX:+UseParallelGC

在此我们可以看出,我们的虚拟机使用了ParallelScavenge+Serial Old收集器组合进行垃圾收集。


GC日志解析
主体日志解析

研究完Java虚拟机的参数,开始GC日志的信息的分析

2021-05-10T10:37:58.612+0800: 10.576: [GC (Allocation Failure) [PSYoungGen: 524800K->12561K(611840K)] 524800K->12649K(2010112K), 0.0345720 secs] [Times: user=0.05 sys=0.01, real=0.03 secs]

GC :表明进行了一次垃圾回收,前面没有Full修饰,表明这是一次Minor GC ,注意它不表示只GC新生代。
Allocation Failure:表示本次引起GC的原因是因为在新生代中没有足够的空间能够存储新的数据了。
PSYoungGen: 524800K->12561K(611840K)
理解这行数据,需要我们在复习一个知识点。

串行收集器:

DefNew:是使用-XX:+UseSerialGC(新生代,老年代都使用串行回收收集器)。

并行收集器:

ParNew:-XX:+UseParNewGC(新生代使用并行收集器,老年代使用串行回收收集器)或者-XX:+UseConcMarkSweepGC(新生代使用并行收集器,老年代使用CMS)。

PSYoungGen:使用-XX:+UseParallelOldGC(新生代,老年代都使用并行回收收集器)或者-XX:+UseParallelGC(新生代使用并行回收收集器,老年代使用串行收集器)

garbage-first heap:使用-XX:+UseG1GC(G1收集器)

通过PSYoungGen可以看出,本次进行的是新生代GC

GC (Allocation Failure) [PSYoungGen: 524800K->12561K(611840K)] 524800K->12649K(2010112K), 0.0345720 secs] [Times: user=0.05 sys=0.01, real=0.03 secs

:YoungGC前新生代的内存占用量;
:YoungGC后新生代的内存占用量;
:新生代总内存大小;
:YoungGC前JVM堆内存占用量;
:YoungGC后JVM堆内存使用量;
:JVM堆内存总大小;
:YoungGC耗时
:YoungGC用户耗时;
:YoungGC系统耗时;
:YoungGC实际耗时;

我们再来看一下年老代的GC日志:

年老代GC的叫法:Full GC或者FGC或者MajorGC或者重GC

在这里插入图片描述
日志格式上与新生代的差不多,只是多了一些关键字:

Full GC (Ergonomics):表示进行了FullGC
ParOldGen:Old区
Metaspace:元空间区

理解了这些关键字后,再结合上面的解读,就能轻松的读懂这条GC日志了!

GC日志中的堆信息
Heap
 PSYoungGen      total 646144K, used 93638K [0x00000000d5580000, 0x0000000100000000, 0x0000000100000000)
  eden space 615936K, 10% used [0x00000000d5580000,0x00000000d9375668,0x00000000faf00000)
  from space 30208K, 99% used [0x00000000fe280000,0x00000000ffffc218,0x0000000100000000)
  to   space 41472K, 0% used [0x00000000faf00000,0x00000000faf00000,0x00000000fd780000)
 ParOldGen       total 1398272K, used 24456K [0x0000000080000000, 0x00000000d5580000, 0x00000000d5580000)
  object space 1398272K, 1% used [0x0000000080000000,0x00000000817e2160,0x00000000d5580000)
 Metaspace       used 36147K, capacity 36882K, committed 37032K, reserved 1081344K
  class space    used 4518K, capacity 4723K, committed 4776K, reserved 1048576K

当我们知道了PSYoungGen、ParOldGen、 Metaspace分别对应什么分区时,就能非常容易的看懂GC日志中的堆的信息了!这里就不再赘述。

通过分析GC日志能够让我们清楚的了解到JVM虚拟机的状态,以及辅助相关的问题定位,也能帮助我们对jvm内存优化提供一些参考。

~感谢阅读

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LLLDa_&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值