深入理解Java虚拟机之实战OutOfMemoryError

栏目: Java · 发布时间: 6年前

内容简介:“Shallow Heap”:类本身元数据的大小。“Retained Heap”:该类以及它引用的其他类所占用空间的总和

Java虚拟机中哪些区域会发生OOM

堆、虚拟机栈、本地方法栈、方法区、直接内存

堆OOM

测试程序:

/**
 * VM Args: -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
 * User:wangs
 * Date:2018/8/23
 */
public class HeapOOM {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        while (true) {
            list.add(new Object());
        }
    }
}
复制代码

运行结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid18148.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Heap dump file created [13355339 bytes in 0.137 secs]
    at java.util.Arrays.copyOf(Arrays.java:3210)
    at java.util.Arrays.copyOf(Arrays.java:3181)
    at java.util.ArrayList.grow(ArrayList.java:261)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
    at java.util.ArrayList.add(ArrayList.java:458)
    at com.thinkinjava.jvm.HeapOOM.main(HeapOOM.java:18)
复制代码

用MAT工具打开堆快照文件:

深入理解 <a href='https://www.codercto.com/topics/22013.html'>Java</a> 虚拟机之实战OutOfMemoryError

“Shallow Heap”:类本身元数据的大小。“Retained Heap”:该类以及它引用的其他类所占用空间的总和

深入理解Java虚拟机之实战OutOfMemoryError

深入理解Java虚拟机之实战OutOfMemoryError 大概的分析步骤就是这样,关于MAT的使用,可以去多了解下。

栈OOM

  • 线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError。
  • 如果虚拟机在扩展栈时无法申请到足够的内存,则抛出OOM。
    测试程序:
/**
 * VM Args:-Xss128k
 * User:wangs
 * Date:2018/8/27
 */
public class StackOOM {

    private int stackLength = 1;

    public static void main(String[] args) {
        StackOOM stackOOM = new StackOOM();
        try {
            stackOOM.test();
        } catch (Throwable e) {
            System.out.println("stack length:" + stackOOM.stackLength);
            throw e;
        }
    }
    private void test() {
        stackLength++;
        test();
    }
}
复制代码

运行结果:

stack length:994
Exception in thread "main" java.lang.StackOverflowError
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:25)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
    at com.thinkinjava.jvm.StackOOM.test(StackOOM.java:26)
复制代码

上篇文章 深入理解Java虚拟机之栈帧 ,介绍了栈帧,我们来回顾一下:栈帧是保存在虚拟机栈中的,栈帧是用来存储数据和存储部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。栈帧越大,栈深度越小。方法参数过多或者局部变量过多都会使栈深度变小,如果超过-xss设置的栈内存容量,就会导致栈溢出。

方法区OOM

测试程序:

/*
 * VM Args: -XX:PermSize=10m -XX:MaxPermSize=10m
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }
}
复制代码

在JDK1.6及之前版本中,由于常量池分配在永久代中(即方法区),我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的容量。运行时常量池溢出: java.lang.OutOfMemoryError: PermGen space

JDK1.7常量池不在存储对象,而是存储对象的引用。修改虚拟机参数 -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError ,运行结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.Integer.toString(Integer.java:401)
    at java.lang.String.valueOf(String.java:3099)
    at com.thinkinjava.jvm.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:14)
复制代码

异常的意思是程序花在垃圾回收上的时间太多,却没有什么效果。默认的话,如果98%的时间都花在GC上并且回收了才不到2%的空间的话,虚拟机就会抛这个异常。

JDK1.8移除了永久代,类的元数据信息存储在元空间。元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过 -XX:MetaspaceSize -XX:MaxMetaspaceSize 参数来指定元空间的大小。

测试程序:

/**
 * VM Args:-XX:MaxMetaspaceSize=10m
 * User:wangs
 * Date:2018/8/27
 */
public class MetaspaceOOM {
    static ClassPool classPool = ClassPool.getDefault();

    public static void main(String[] args) throws Exception {
        int i = 1;
        while (true){
            classPool.makeClass("com.thinkinjava.jvm" + i++).toClass();
        }
    }
}
复制代码

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
    at javassist.ClassPool.toClass(ClassPool.java:1170)
    at javassist.ClassPool.toClass(ClassPool.java:1113)
    at javassist.ClassPool.toClass(ClassPool.java:1071)
    at javassist.CtClass.toClass(CtClass.java:1264)
    at com.thinkinjava.jvm.Metaspace.main(Metaspace.java:16)
复制代码

直接内存OOM

测试程序:

/**
 * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
 * User:wangs
 * Date:2018/8/27
 */
public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}
复制代码

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError
    at sun.misc.Unsafe.allocateMemory(Native Method)
    at com.thinkinjava.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:21)复制代码

如果读完觉得有收获的话,欢迎点赞、关注、加公众号【Java在线】,查阅更多精彩历史!!!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++ Primer Plus

C++ Primer Plus

Stephen Prata / 张海龙、袁国忠 / 人民邮电出版社 / 2012-6-19 / 99.00元

C++是在C语言基础上开发的一种集面向对象编程、通用编程和传统的过程化编程于一体的编程语言,是C语言的超集。本书是根据2003年的ISO/ANSI C++标准编写的。通过大量短小精悍的程序详细而全面地阐述了C++的基本概念和技术。全书分为18章和10个附录,分别介绍了C++程序的运行方式、基本数据类型、复合数据类型、循环和关系表达式、分支语句和逻辑操作符、函数重载和函数模板、内存模型和名称空间、类......一起来看看 《C++ Primer Plus》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具