欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

堆溢出处理

程序员文章站 2022-07-15 15:46:37
...

在Java程序运行过程中,对象会不断的被新建和回收,而对象大部分情况下是放在堆空间中的,所以一旦对象太多导致堆空间不足,就会抛出OOM异常,也就是堆内存溢出了。

就像查案一样,程序出现问题的时候,先要保持现场信息,这样才方便排查问题,而JVM也为开发这提供了这样的手段,
使用参数-XX:+HeapDumpOnOutOfMemoryError,让内存溢出的时候可以导出整个堆的信息,然后再加上-XX:HeapDumpPath参数,把整个堆的信息导出到开发指定的文件路径,方便查找。两个参数配合就做到了当出现OOM时,可以尽可能的保存下现场信息。

接下来指定程序使用的虚拟机的工作模式为Server,然后指定最大堆大小为10M同时打印GC日志,最后再加上上述的两个参数,整体如下:
堆溢出处理
测试代码:

import com.google.common.collect.Lists;

import java.util.List;

/**
 * 堆溢出导出文件
 */
public class DumpOOM {

    public static class User {
        private byte[] p;
    }

    public static User createUser() {
        User user = new User();
        //大约1M大小
        user.p = new byte[1 * 1024 * 1024];
        return user;
    }

    public static void main(String[] args) {
        List list = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            list.add(createUser());
            System.out.println("list中的数量:" + list.size());
        }
    }
}

以上代码实现的逻辑就是,循环创建User对象实例,并加入到集合list中,因为设置的最大堆大小为10M,而User实例中单单一个p属性就大约为1M了,所以最后的结果肯定会发生OOM。

运行结果如下:
堆溢出处理
从输出结果可以发现,User实例有7个,同时也把堆信息文件导出到指定路径了。

使用Java VisualVM工具分析下堆信息文件,展示如下:
堆溢出处理

发现byte[]类型占据的空间最多,点击去看下实例视图,如下:
堆溢出处理
从大到小排列下,会发现前7个实例大致都是1M左右,然后这7个实例都和DumoOOM类下的User类的p属性相关。

回顾下之前程序的输出,list中的数量也只有7个,后面就抛出OOM了,数量和实例视图是对的上的。

总结

堆溢出时可以先导出堆信息文件保存,然后再配合上Java VisualVM工具找出导致堆溢出的对象。

相关标签: JVM 堆溢出处理