你知道的越多,你不知道的越多
上次给老公们说过了死循环cpu飙高的排查过程,今天就带着老公们看看堆内存溢出我们一般怎么排查的。
在排查之前,我想jvm的基础知识大家应该都是了解了的吧?
行行行,诶真实拿你们没办法,那我就带大家回温一下JVM的内存模型(这玩意跟JAVA内存模型JMM可不一样,不要记错了)
今天我就直说堆,因为溢出是发送在堆中的。
JVM堆内存被分为两部分:年轻代(Young Generation)和老年代(Old Generation)。
年轻代年轻代是所有新对象产生的地方。当年轻代内存空间被用完时,就会触发垃圾回收。这个垃圾回收叫做Minor GC。
被分为3个部分——Enden区和两个Survivor区。
年老代内存里包含了长期存活的对象和经过多次Minor GC后依然存活下来的对象,通常会在老年代内存被占满时进行垃圾回收。
老年代的垃圾收集叫做Major GC,Major GC通常是跟full GC是等价的,收集整个GC堆。
Full GC定义是相对明确的,就是针对整个新生代、老生代、元空间(metaspace,java8以上版本取代perm gen)的全局范围的GC。
老公们可以从上图看到年轻代分为了一个Eden区和两个survivor区(S1,S2),survivor区同一时间只会有一个满一个空,交替的。
然后就是GC到一定的阈值到老年代,今天不讲永久代所以忽略Mataspace。
今天我就用一个JDK自带的工具jvisualvm来给大家演示一波怎么操作的,因为这玩意谁都有,你去命令行敲一下jvisualvm就出来了(Mac是这样的,不知道Windows是怎么样子的)。
操作界面:
超时,不进行服务,服务挂掉,接口不在服务这样的异常问题。
那模拟也很简单,我写个循环一直往List丢数据,不使用list就能看到现象了
老公们可以看到图形化界面还是很清晰明了的,这个是Visual GC的插件
大家点击菜单栏的插件,然后安装就好了,安装完了记得点击激活。
可以看到不释放,堆空间就一直上去,直到OOM(out of memory)
这个时候我们就dump下来堆信息看看
会dump出一个这样的hprof快照文件,可以用jvisualvm本身的系统去分析,我这里推荐MAT吧,因为我习惯这个了。
MAT :下载地址
下来好了我们可以看到mat已经分析了我们的文件
你看他就是个暖男,都帮我们分析出来了一个问题,我们点进去看看
他发现了是ArrayList的问题了,我们再往下看看
看到了嘛,具体代码的位置都帮我们定位好了,那排查也就是手到擒来的事情了。
上面我们使用工具jump了,那怎么去服务器上jump呢?
jmap -dump:format=b,file=<dumpfile.hprof> <pid>
有老公可能问了,不是所有的故障当时我们都在场的,无法及时jump,那也简单
-XX:+HeapDumpOnOutOfMemoryError
配置这玩意之后,oom的时候会自动jump的,到时候拿快照分析一波就好了。
MAT的功能还有很多的,百度谷歌太多工具文了,我就不做重复的工作了,比如还可以排查对象的强弱引用,还可以查看引用链等等。
还有个只写这么点的原因是有点晚了,顶不住了,最近不拍视频也是因为事情多了,有点小忙,希望老公们体量,对了Redis的分布式锁已经在安排的路上了。
我是敖丙,一个在互联网苟且偷生的工具人。