【Java】是时候了解一波如何排除堆内存溢出了?
在排查之前,我想小伙伴对JVM内存结构都应该是了解的吧,不了解的传送门走一波:
- 排查之前,我脚的我们必须得了解一波啥是内存溢出?(传送门在这里:《你必须了解的内存溢出和内存泄漏》)
内存溢出:系统已经不能再分配出多余的空间给你所使用了。
内存泄漏:在你使用一块资源时,给他分配了一部分空间;当你不再使用了之后,并没有回收它,但是它确实没有用了,就造成了内存泄漏。
- 我们这里就用JDK自带的工具【jvisualvm】来分析一波,因为这玩意谁都能轻易操作
打开【jdk】路径,然后进入到【bin】目录,就会看到个这玩意:
没错,是它,是它 ,就是它,我们的朋友小哪吒~~~咳咳,sorry,串场了,就是这么个玩意,来我们双击戳它:
可以很清晰的看到【CPU】、【堆】、【类】、【线程】各个情况,不过这玩意应该咋看呢?
- 话不多说,我们先撸个代码先:
public class OutOfMemeryDemo { private static final int KB = 1024; public static void main(String[] args) { int size = KB * KB * 8; List<byte[]> list = new ArrayList<>(); for (int i = 0; i < size; i++) { try { Thread.sleep(500); //每搁1秒执行一次 } catch (InterruptedException e) { e.printStackTrace(); } list.add(new byte[i]);//每次循环比上一次多创建一个对象 } } }
运行后,我们可以看到【jvisualvm】结果,可以看到堆内存在以梯度的样式分配内存:
终于到最后,它还是内存溢出了,很完美~
- 我们在【jvisualvm】中安装一个插件【Visual GC】,点击【工具 - 插件】,安装过程就略过了,我觉得我没用过电脑的外婆应该都so easy,由于该插件国外提供,下载失败的小伙伴也可以试试本地下载后安装:
【Visual GC】看到的GC情况会更加直观:
- 监事情况看过之后,我们该试着如何排查问题了,我们可以把堆的内存情况下载出来:
点击【堆 dump】后,会生成一个快照,我们可以通过快照看到类使用情况,如下图:
- 不过【jvisualvm】上描述的太抽象了,恕鄙人脑洞有限,所以也采用【MAT(由于是Eclipse插件,所以必须要有eclipse)】来分析快照
1》先把快照下载下来,我们右键快照,并另存为到文件夹中:
2》可以看到,其实就是这么个玩意(老铁们,清忽略我凌乱的文件夹):
3》然后我们导入快照文件,可以发现【MAT】真的是个暖心小姐姐,她已经帮我分析好了问题了:
我们点击【Details】,可以看到【ArrayList】出了问题,也就是我们刚才定义的【ArrayList】:
我们再往下看,都可以直接看到【MAT】帮我们定位到哪一行问题:
MAT可真是个知心大姐!不过MAT还有很多功能,不过具体我这里就不做描述了,小伙伴们可自行百度谷歌~~~绝对有新大陆~~~
- 不过以上都是我们用的客户端工具获取的快照,那么我们在服务器上如何下载快照呢?
我们可以使用如下命令:
jmap -dump:format=b,file=<dumpfile.hprof> <pid>
有的小伙伴可能是在远程工作,所以不能马上进行指令获取快照,不过也不要慌,我们可以配置一下参数:
-XX:+HeapDumpOnOutOfMemoryError
这个东西就神奇了,配置这玩意之后,当系统出现【OOM】,就会自动生成一个【堆 Dump】
学而不思则罔 思而不学则殆 !