051-如何解决JVM堆内存溢出

366次阅读
没有评论

共计 1888 个字符,预计需要花费 5 分钟才能阅读完成。

动手实验: JVM堆内存溢出的时候,应该如何解决?

1、前文回顾

上一篇文章已经给大家分析了栈内存溢出是如何来解决的,这篇文章我们给大家分析一下最常见的堆内存溢出是如何来解决的。

2、示例代码

我们还是沿用之前的示例代码:

051-如何解决JVM堆内存溢出

采用的JVM参数如下:

-Xms10m
-Xmx10m
-XX:+PrintGCDetails
-Xloggc:gc.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC

接着我们运行上述程序。

3、运行后的观察

其实堆内存溢出的现象也是很简单的,在系统运行一段时间之后,直接会发现系统崩溃了,然后登录到线上机器检查日志文件

先看到底为什么崩溃:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to ./java_pid1023.hprof ...
Heap dump file created [13409210 bytes in 0.033 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

这个就很明显告诉我们,是Java堆内存溢出了,而且他还给我们导出了一份内存快照。

所以此时我们GC日志都不用分析了,因为堆内存溢出往往对应着大量的GC日志,所以你分析起来是很麻烦的。

此时直接将线上自动导出的内存快照拷贝回本地笔记本电脑,然后用MAT分析即可。

4、用MAT分析内存快照

采用MAT打开内存快照之后会看到下图:

051-如何解决JVM堆内存溢出

这次MAT非常简单,直接在内存泄漏报告中告诉我们,内存溢出原因只有一个!那就是这个问题,因为他没提示任何其他的问题。

我们这次来给大家仔细分析一下MAT给我们的分析报告。

首先看下面的句子:The thread java.lang.Thread @ 0x7bf6a9a98 main keeps local variables with total size 7,203,536 (92.03%) bytes。

这个意思就是main线程通过局部变量引用了7230536个字节的对象,大概就是7MB左右。

考虑到我们总共就给堆内存10MB,所以7MB基本上个已经到极限了,是差不多的。

我们接着看:The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader"。

这句话的意思就是内存都被一个实例对象占用了,就是java.lang.Object[]。

我们肯定不知道这个是什么东西,所以得往下看,点击Details

051-如何解决JVM堆内存溢出

在Details里我们能看到这个东西,也就是占用了7MB内存的的java.lang.Object[],他里面的每个元素在这里都有,我们看到是一大堆的java.lang.Object。那么这些java.lang.Object不就是我们在代码里创建的吗?

至此真相大白,我们已经知道,就是一大堆的Object对象占用了7MB的内存导致了内存溢出。

接着下一个任务就是知道这些对象是怎么创建出来的,那么我们怎么找呢?回到之前的上一级页面,各位看下图。

051-如何解决JVM堆内存溢出

这个是说可以看看创建那么多对象的线程,他的一个执行栈,这样我们就知道这个线程执行什么方法的时候创建了一大堆的对象。

051-如何解决JVM堆内存溢出

大家看上面的调用栈,其实说的很明显了,在Demo3.main()方法中,一直在调用ArrayList.add()方法,然后此时直接引发了内存溢出。所以我们只要在对应代码里看一下,立马就知道怎么回事了。

接下来优化对应的代码即可,就不会发生内存溢出了。


正文完
 0
yangleduo
版权声明:本站原创文章,由 yangleduo 于2023-05-15发表,共计1888字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。