带大家回温一下JVM的内存模型(这玩意跟JAVA内存模型JMM可不一样,不要记错了)

今天我就直说堆,因为溢出是发送在堆中的。

JVM堆内存被分为两部分:年轻代(Young Generation)和老年代(Old Generation)。

年轻代

年轻代是所有新对象产生的地方。当年轻代内存空间被用完时,就会触发垃圾回收。这个垃圾回收叫做Minor GC。

年轻代被分为3个部分——Enden区和两个Survivor区。

年轻代空间的要点:

  1. 大多数新建的对象都位于Eden区。
  2. 当Eden区被对象填满时,就会执行Minor GC,并把所有存活下来的对象转移到其中一个survivor区。
  3. Minor GC同样会检查存活下来的对象,并把它们转移到另一个survivor区。这样在一段时间内,总会有一个空的survivor区。
  4. 经过多次GC周期后,仍然存活下来的对象会被转移到年老代内存空间,通常这是在年轻代有资格提升到年老代前通过设定年龄阈值来完成的。

年老代

年老代内存里包含了长期存活的对象和经过多次Minor GC后依然存活下来的对象,通常会在老年代内存被占满时进行垃圾回收。

GC种类

Major GC

老年代的垃圾收集叫做Major GC,Major GC通常是跟full GC是等价的,收集整个GC堆。

分代GC

  1. Young GC:只收集年轻代的GC
  2. Old GC:只收集年老代的GC(只有CMS的concurrent collection是这个模式)
  3. Mixed GC:收集整个young gen以及部分old gen的GC(只有G1有这个模式)

Full GC

Full GC定义是相对明确的,就是针对整个新生代、老生代、元空间(metaspace,java8以上版本取代perm gen)的全局范围的GC。

java老年代越来越大 jvm老年代爆满_后端

java老年代越来越大 jvm老年代爆满_java老年代越来越大_02

老公们可以从上图看到年轻代分为了一个Eden区和两个survivor区(S1,S2),survivor区同一时间只会有一个满一个空,交替的。

然后就是GC到一定的阈值到老年代,今天不讲永久代所以忽略Mataspace。

那怎么分析呢?

今天我就用一个JDK自带的工具jvisualvm来给大家演示一波怎么操作的,因为这玩意谁都有,你去命令行敲一下jvisualvm就出来了(Mac是这样的,不知道Windows是怎么样子的)。

操作界面:

java老年代越来越大 jvm老年代爆满_开发语言_03

java老年代越来越大 jvm老年代爆满_java_04

 

一般什么情况可能是出现了溢出呢?

超时,不进行服务,服务挂掉,接口不在服务这样的异常问题。

那模拟也很简单,我写个循环一直往List丢数据,不使用list就能看到现象了

java老年代越来越大 jvm老年代爆满_java_05

java老年代越来越大 jvm老年代爆满_开发语言_06

 

可以看到图形化界面还是很清晰明了的,这个是Visual GC的插件

java老年代越来越大 jvm老年代爆满_后端_07

java老年代越来越大 jvm老年代爆满_后端_08

 

大家点击菜单栏的插件,然后安装就好了,安装完了记得点击激活。

java老年代越来越大 jvm老年代爆满_开发语言_09

java老年代越来越大 jvm老年代爆满_java老年代越来越大_10

 

可以看到不释放,堆空间就一直上去,直到OOM(out of memory)

java老年代越来越大 jvm老年代爆满_java老年代越来越大_11

这个时候我们就dump下来堆信息看看

java老年代越来越大 jvm老年代爆满_java老年代越来越大_12

会dump出一个这样的hprof快照文件,可以用jvisualvm本身的系统去分析,我这里推荐MAT吧,因为我习惯这个了。

java老年代越来越大 jvm老年代爆满_jvm_13

MAT :下载地址

下来好了我们可以看到mat已经分析了我们的文件

java老年代越来越大 jvm老年代爆满_开发语言_14

你看他就是个暖男,都帮我们分析出来了一个问题,我们点进去看看

java老年代越来越大 jvm老年代爆满_java_15

他发现了是ArrayList的问题了,我们再往下看看

java老年代越来越大 jvm老年代爆满_java老年代越来越大_16

看到了嘛,具体代码的位置都帮我们定位好了,那排查也就是手到擒来的事情了。

java老年代越来越大 jvm老年代爆满_开发语言_17

延伸点

上面我们使用工具jump了,那怎么去服务器上jump呢?

jmap -dump:format=b,file=<dumpfile.hprof> <pid>

有人可能问了,不是所有的故障当时我们都在场的,无法及时jump,那也简单

-XX:+HeapDumpOnOutOfMemoryError

配置这玩意之后,oom的时候会自动jump的,到时候拿快照分析一波就好了。

MAT的功能还有很多的,百度谷歌太多工具文了,我就不做重复的工作了,比如还可以排查对象的强弱引用,还可以查看引用链等等。