「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。
1 前言
关于JVM内存区域,相信大家都耳熟能详,无非就堆、栈、方法区那几个。
正常开发工作中,除了使用递归之外,很少会出现栈溢出(StackOverFlow)的情况。因此我们的关注点也就在堆和方法区了。
在JDK8之后,方法区的实现变为了元空间,并且字符串常量池等迁移到了堆中,于是乎看懂堆也就是看懂了JVM内存。排除掉JVM监控工具例如jvisualm等,看GC日志也是看JVM异常的技能之一。
这一期我们就简单讲一下GC日志,以下是本期JVM的配置
-Xms5m
-Xmx1024m
-XX:NewRatio=1
-XX:MetaspaceSize=100m
-XX:MaxMetaspaceSize=100m
2 日志命令
2.1 -XX:+PrintGC
GC (Allocation Failure) :
可以看到是由于分配失败导致的GC,堆的大小=5M,具体是新生代还是老年代发生的GC完全看不出,所以我们需要用另一个命令
2.2 -XX:+PrintGCDetails
PSYoungGen代表Parallel Scavenge 新生代收集器。第二个框代表新生代大小总共2560K,回收后从2048K减少到512K第三个框代表堆大小总共5632k,回收后从2048k减少到825k。user此次垃圾回收, 垃圾收集线程消耗的所有CPU时间(Total CPU time).sys操作系统调用(OS call) 以及等待系统事件的时间(waiting for system event)real应用程序暂停的时间(Clock time)。 由于有些收集器并不是串行的,所以一定程度上real不一定等于user + sys
3 场景
3.1 项目启动场景
-XX:+PrintGCDetails
项目刚启动时,由于我们的Xms和Xmx大小设置不一致,导致多次发生GC,并且新生代和堆的大小一直在增大(看箭头),并且发生了FullGC。
- PSYoungGen :新生代用Parallel Scavenge收集器
- ParOldGen: 老年代用的Parallel Old收集器
- MetaSpace 未发生变化,总的大小为1G左右
3.2 创建对象过大场景
- 定义大对象
-
通过循环创建大对象
-
GC日志
可以看到
新生代回收的内容大小基本上等于堆回收的内容大小,如果差距很大,表明老年代也进行了回收,也就是进行了Full GC
3.3 内存泄漏场景
实际场景中,如果服务调用很慢,除了考虑DB连接,服务器负载,OOM同样也是需要考虑的因素。
可以把OOM分为内存溢出和内存泄漏,内存溢出的常见现象为频繁发生新生代GC,这时候临时处理就比较简单了,增大JVM内存就能马上解决。而如果是内存泄漏,常见现象为频繁发生full GC。我们来模拟下内存泄漏:
-
首先定义类变量
-
通过ArrayList连接BigData对象使其不被标记,导致不被回收
-
查看GC日志
因为内存回收不掉,所以由于晋升机制对象会移到老年代。从而发生了FullGC。
多次Full GC 后,发生了OutOfMemoryError。
结尾
这一期简单介绍了GC日志,有收获的同学点个赞呗。
下期可能也是这方面的内容,也可能是ELK的东西。