Java内存区域之堆内存溢出

堆内存溢出

Java内存区域Java堆章节介绍过,如果Java堆中没有内存完成新实例分配,且无法再扩展(通过-Xmx指定了上限或受限于物理内存),会抛出OutOfMemoryError异常。

Java堆用于存储对象实例,我们只要不断的创建对象,并保证GC Roots到对象之间有可达路径来避免垃圾回收器清除这些对象,那么随着对象数量不断增加,总容量触及堆的容量限制后就会产生内存溢出异常。

堆内存溢出示例

示例采用Win10下的JDK 8运行,不同的JDK版本可能会有不同的结果。版本信息如下:
在这里插入图片描述
示例代码如下:

package jvm.oom;

/**
 * 虚拟机参数:-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/dump/ -verbose:gc
 *
 * @author faith.huan 2020-01-06 22:02
 */
public class JavaHeapOom {

    private static final int ONE_MB = 1024 * 1024;

    public static void main(String[] args) {
        byte[][] bytes = new byte[10][];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = new byte[ONE_MB];
            System.out.println("创建第" + (i + 1) + "个1M字节数组成功");
        }
    }

}

示例参数解释:

参数解释
-Xms设置Java堆初始大小,默认单位b,可用单位:K,k,M,m,G,g ,本例中-Xms10m表示堆初始空间10MB
-Xmx设置Java堆最大大小,默认单位b,可用单位:K,k,M,m,G,g ,本例中-Xmx10m表示堆最大空间10MB
-XX:+HeapDumpOnOutOfMemoryError当发生内存溢出时使用heap profiler (HPROF) 将Java堆记录到当前路径文件中,+HeapDumpOnOutOfMemoryError表示激活此设置即记录到文件,-HeapDumpOnOutOfMemoryError表示不激活此设置即不记录到文件,默认为不激活。
-XX:HeapDumpPath指定激活HeapDumpOnOutOfMemoryError选项时Java堆记录的文件路径及名称,默认为当前路径-Idea运行时的Working directory,文件名为java_pidpid.hprofpid表示进程id。-XX:HeapDumpPath=D:/dump/表示记录文件到D:/dump/目录下
-verbose:gc显示垃圾收集日志信息.

IDEA运行参数截图
在这里插入图片描述
程序运行日志

创建第11M字节数组成功
创建第21M字节数组成功
创建第31M字节数组成功
创建第41M字节数组成功
创建第51M字节数组成功
创建第61M字节数组成功
[GC (Allocation Failure) [PSYoungGen: 1912K->496K(2560K)] 8056K->6945K(9728K), 0.0007925 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
创建第71M字节数组成功
[GC (Allocation Failure) --[PSYoungGen: 1583K->1583K(2560K)] 8033K->8041K(9728K), 0.0009478 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 1583K->1445K(2560K)] [ParOldGen: 6457K->6425K(7168K)] 8041K->7871K(9728K), [Metaspace: 3133K->3133K(1056768K)], 0.0041284 secs] [Times: user=0.13 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) --[PSYoungGen: 1445K->1445K(2560K)] 7871K->7911K(9728K), 0.0008741 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 1445K->1409K(2560K)] [ParOldGen: 6465K->6443K(7168K)] 7911K->7853K(9728K), [Metaspace: 3133K->3133K(1056768K)], 0.0038629 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/dump/\java_pid11336.hprof ...
Heap dump file created [8880160 bytes in 0.012 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at jvm.oom.JavaHeapOom.main(JavaHeapOom.java:15)
Heap
 PSYoungGen      total 2560K, used 1595K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 77% used [0x00000000ffd00000,0x00000000ffe8ee18,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 6443K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 89% used [0x00000000ff600000,0x00000000ffc4ad08,0x00000000ffd00000)
 Metaspace       used 3240K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 351K, capacity 388K, committed 512K, reserved 1048576K

通过上面的日志可以看出,共创建了7个1M的字节数组,在创建第8个时,发生内存溢出。内存溢出时堆内存情况如下

区域名称总内存已用内存使用比例剩余内存
eden space 伊甸区2048K1595K77%453K
from space 幸存区1512K0K0%512K
to space 幸存区2512K0K0%512K
OldGen 老年代7168K6443K89%725K

从上面表格中可见,年轻代(eden+from survior+to survior),老年代剩余空间都不足1M,无法容纳第八个1M的字节数组,且前面7个又无法进行回收,而且设置了堆上限10M,因此发生内存溢出异常。

堆栈溢出分析

使用Eclipse Memory Analyzer对上面例子发生OOM时导出的堆快照文件java_pid11336.hprof进行分析。
Eclipse Memory Analyzer下载地址:https://www.eclipse.org/mat/downloads.php,根据自己的操作系统选择合适的版本,此处我选择Win64版本
在这里插入图片描述
下载完成后,进行解压,进入mat目录,双击MemoryAnalyzer.exe启动软件。
依次点击File->Open Heap Dump
在这里插入图片描述
选择上面示例产生的java_pid11336.hprof文件,然后点击打开按钮
在这里插入图片描述
勾选Leak Suspects Report(内存泄漏报告),点击Finish
在这里插入图片描述
报告显示找到一个可疑问题,即主线程持有了7M的bytes[][]对象。
在这里插入图片描述
点击报告中的See stacktrace连接可疑查看堆栈信息,定位到具体的代码,本示例点击后定位到JavaHeapOom.java的第15行,如下图所示
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值