StackOverFlow & OutOfMemory

StackOverFlow & OutOfMemory

两者都为 Error,广义上的“异常”

StackOverflow

通常为 Java 虚拟机栈内存不够,JVM 对方法栈只有入栈和出栈的操作,所以在此处要报异常,让方法一直加入到方法栈中,而不出栈,将栈爆满,即可报异常。

举个栗子(最简单的栗子,无限递归)

public class StackErrorTest {

    private static int count = 0;

    public static void main(String[] args) {
        System.out.println(count++);
        main(args);
    }

}

image-20220330210642124

可以通过增加栈内存来解决部分问题,但不是长久解决方法,还是得优化代码。(-Xss1024m)(不建议设置太大,一般1M即可)栈大小设置

image-20220330204153419

image-20220330210614699

OOM

oom(java.lang.OutOfMemoryError)

Java heap space

和 StackOverflow 类似,JVM 堆空间不足,对象实例及数组几乎都放在堆空间中,所以可以一直加新的对象让堆空间爆满

举个栗子

import java.util.ArrayList;
import java.util.List;

public class OOMTest {

    public static void main(String[] args) {
        List<O> list = new ArrayList<>();
        while (true){
            list.add(new O(1024*1024*1024));
            System.out.println(list.size());
        }
    }

}

class O{
    private byte[] bs;
    public O(int length){
        this.bs = new byte[length];
    }
}

image-20220330210702560

同理,可以增加堆空间暂时解决问题 -Xms10240m -Xmx10240m

  • -Xms 设置堆空间的初始内存大小 默认为内存 1/64
  • -X 是jvm的运行参数
  • ms memory start
  • -Xmx 设置堆空间最大内存大小 默认为内存 1/4

image-20220330210249143

image-20220330210313164

MetaSpace(jdk8及以上)

属于元空间内存不够,元空间主要存放类信息,在加载过多的类会触发该报错,但在 jdk8 中方法区(8之后叫元空间)采用本地内存,最大值为本地运行内存大小,所以一般不会触发该报错。

修改元空间大小来触发报错

  • -XX:MetaspaceSize=10m
  • -XX:MaxMetaspaceSize=10m

设置初始大小为 10m,设置最大元空间大小为10m

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class JavaMethodAreaOOM {

    public static void main(String[] args) {
        while (true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o,objects);
                }
            });
            enhancer.create();
        }
    }

    static class OOMObject{}
    
}

image-20220630160327552

Direct buffer memory

本地直接内存不足,该内存不使用堆内存,不代表本地直接内存无限大,由于系统内存大小受限,所以本地内存和堆内存总和是有限制的,默认与堆内存大小一致

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class OOM2 {

    public static void main(String[] args) {
        int buffer = 1024 * 1024 * 100;	//100M
        List<ByteBuffer> list = new ArrayList<>();
        int count = 0;
        try {
            while (true){
                ByteBuffer direct = ByteBuffer.allocateDirect(buffer);
                list.add(direct);
                count++;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println(count);
        }
    }

}

image-20220418203612660

posted @ 2022-06-30 16:12  抱糖果彡  阅读(198)  评论(0编辑  收藏  举报