资讯专栏INFORMATION COLUMN

那些年,我们遇到的OOM

LeanCloud / 2620人阅读

摘要:内存模型先聊聊内存模型,在网上找到一张有直接内存的图片,方便后面讨论这张图真是常看常新,今天我们从内存溢出的角度重新再审视一遍。

JVM内存模型

先聊聊jvm内存模型,在网上找到一张有直接内存的图片,方便后面讨论

这张图真是常看常新,今天我们从内存溢出的角度重新再审视一遍。
方法区,也称非堆,hotspot中,1.7叫perm区,1.8叫元空间,因此这个区域溢出,1.7就是OutOfMemoryError: PermGen space,1.8是OutOfMemoryError: Metaspace

堆溢出比较常见,OutOfMemoryError: Java heap space

虚拟机栈的溢出是 StackOverflowError

本地方法栈会出现 java.lang.OutOfMemoryError : unable to create new native Thread

直接内存会抛出 OutOfMemoryError: Direct buffer memory

以下将逐个撑爆这些空间

先来撑爆虚拟机栈 StackOverflowError

不停地递归调用,jvm不得不在虚拟机栈上分配栈帧空间,从而导致sofe,感兴趣的还可以查看一下递归的次数,可能通过-Xss进行配置,通过命令jinfo -flag ThreadStackSize [pid]可以查看栈空间大小的配置

public class StackOverflowErrorDemo {
    private static void test() {
        test();
    }

    public static void main(String[] args) {
        test();
    }
}
再来撑爆堆吧 OutOfMemoryError: Java heap space

先指定-Xmx8m -Xms8m,然后直接在堆中生成一个8m字节的数组,可以直接看到效果

public class JavaHeapSpaceDemo {
    public static void main(String[] args) {
        byte[] bytes = new byte[8 * 1014 * 1024];
    }
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.meituan.waimai.jvm.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:11)
方法区有分说

如果是1.7,会出现PemGen space, 这要求我们不断往生成类的信息。由于1.7,字符串常量池已经挪到堆中了,所以使用String.intern()并不会导致perm区溢出

public class OOMDemo {
    public static void main(String[] args) {
        String str = "hello";
        List list = Lists.newArrayList();
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            str += (i + "").intern();
            list.add(str);
        }
    }
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at com.meituan.waimai.jvm.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:18)

那要怎么做呢,这里我们需要动态地生成一些类,直到把perm区撑爆,jvm参数配置:-XX:MaxPermSize=8m

    static class OOMTest{}

    public static void main(final String[] args) {
        int i = 0;

        try {
            for (; ; ) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 8 more

将jdk改为1.8,-XX:MaxMetaspaceSize=20m 重新执行上述程序,结果变成Metaspace溢出

java.lang.OutOfMemoryError: Metaspace
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)
at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
at com.meituan.waimai.jvm.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:36)
该对直接内存动手的

配置jvm参数,-XX:MaxDirectMemorySize=8m,然后分配9m的直接内存:

public class DirectMemoryDemo {
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(9 * 1024 * 1024);
    }
}

可以看到

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694)
at java.nio.DirectByteBuffer.(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at com.meituan.waimai.jvm.DirectMemoryDemo.main(DirectMemoryDemo.java:13)
本地方法栈 unable to create new native Thread

不停地创建java线程,就可以把本地方法栈撑爆

public class NativeThreadDemo {
    public static void main(String[] args) {

        for (; ; ) {
            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at com.meituan.waimai.jvm.NativeThreadDemo.main(NativeThreadDemo.java:21)

这个程序跑完忘了关,结果一会mac重启了,非常可怕。。。。
关于unable to create new native Thread,知乎上有个非常深刻地讨论
https://www.zhihu.com/questio...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76036.html

相关文章

  • 07.Android之多媒体问题

    摘要:加载图的机制是什么,为何不会内存泄漏自定义可拖动的显示高清大图的技术博客大总结提供一个设置图片的入口,里面去获得图片的真实的宽度和高度,以及初始化我们的重写,在里面根据用户移动的手势,去更新显示区域的参数。 目录介绍 7.0.0.1 加载bitmap图片的时候需要注意什么?为何bitmap容易造成OOM?如何计算Bitmap占用内存? 7.0.0.2 如何理解recycle释放内存问...

    eechen 评论0 收藏0
  • 2016Java面试题整理

    摘要:和的区别来自类,和来自类调用方法的过程中,线程不会释放对象锁。机制在使用迭代器的过程中有其他线程修改了,那么将抛出,这就是所谓机制。 面试是我们每个人都要经历的事情,大部分人且不止一次,这里给大家总结最新的2016年面试题,让大家在找工作时候能够事半功倍。 1 Switch能否用string做参数? a.在 Java 7 之前, switch 只能支持byte,short,char,i...

    tianren124 评论0 收藏0
  • 金九银十中,看看这31道Android面试题

    摘要:静态集合类引起内存泄露主要是,等,如果是静态集合这些集合没有及时的话,就会一直持有这些对象。关于合理使用内存,其实就是避免内存泄露中已经说明。参数原生参数元素需要支持机制参考进程线程管理一消息机制的框架这个系类。 阅读目录 1.如何对 Android 应用进行性能分析 2.什么情况下会导致内存泄露 3.如何避免 OOM 异常 4.Android 中如何捕获未捕获的异常 5.ANR 是...

    call_me_R 评论0 收藏0
  • 还在使用SimpleDateFormat?

    摘要:线程挂起,线程继续走,还会被继续使用方法,而这时用的是线程设置的值了,而这就是引发问题的根源,出现时间不对,线程挂死等等。建议为每个线程创建单独的格式实例。其中工作队列使用的是,源码头部的注释中有说明截取的部分。 阅读本文大概需要 3.2 分钟。 前言 日常开发中,我们经常需要使用时间相关类,想必大家对SimpleDateFormat并不陌生。主要是用它进行时间的格式化输出和解析,...

    LittleLiByte 评论0 收藏0
  • Bitmap避免OOM

    摘要:我知道最近世麟心情是错综复杂,但还好的是绝大多数程序员都是特别有善心的。如果图像数据较大就会造成对象申请的内存较多,如果图像过多就会造成内存不够用自然就会出现的现象。第二次将设置为再次调用函数时就能生成了。 目录介绍 01.先看一个需求分析案例 02.Bitmap占用内存介绍 03.影响Bitmap占用内存因素 04.图像加载的方式 05.加载图像内存去哪里了 06.具体实现加载图片...

    EastWoodYang 评论0 收藏0

发表评论

0条评论

LeanCloud

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<