谈谈你对OOM的认识

148 阅读2分钟

OOM分好多种,本文就结合代码demo做个总结,既方便自己温故知新,又能和xdm一起学习进步

1. 栈oom

/**
 * @description:  java.lang.StackOverflowError
 *                -Xss512K 设置栈空间大小  一般512K到1024K
 *                Exception in thread "main" java.lang.StackOverflowError
 *                就是递归调用的时候没有找到出口,导致栈的空间被撑爆了,一般我们设置栈的空间,一般512K到1024K
 * @author: Ding Yawu
 * @create: 2022/4/17 3:22 PM
 */
public class StackOverflowerrorDemo {

    public static void main(String[] args) {
        StackOverflowError();
    }

    public static void StackOverflowError(){
        StackOverflowError();
    }
}

注意这是个错误

image.png

2. 堆oom

/**
 * @description: java.lang.OutOfMemoryError: Java heap space
 *                直接new一个大对象,或者不停地创建对象,设置一下-Xms10M -Xmx10M
 * @author: Ding Yawu
 * @create: 2022/4/17 3:27 PM
 */
public class JavaHeapSpaceDemo {
    public static void main(String[] args) {
        String str = "roy";
        /*while (true){
            str += new Random().nextInt(1111111) + new Random().nextInt(222222);
            str.intern();
        }*/
        byte[] bytes = new byte[1024 * 1024 * 10 ];

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7cb57a6d775f4d15bd0e51a7c663f8cd~tplv-k3u1fbpfcp-watermark.image?)
    }
}

3. GC超过限制导致OOM

/**
 * @description: java.lang.OutOfMemoryError: GC overhead limit exceeded
 *               超过98%的时间用来GC了并且回收不到2%的堆内存
                 -Xms5M -Xmx5M -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5M
 *
 * @author: Ding Yawu
 * @create: 2022/4/17 3:39 PM
 */
public class GCOverheadDemo {
    public static void main(String[] args) {
        int i = 0;
        List<String> list = new ArrayList<>();
        try {
            while (true){
                list.add(String.valueOf(i ++).intern());
            }
        }catch (Throwable e){
            System.out.println("i:" + i);
            e.printStackTrace();
        }
    }
}

4. 直接内存OOM

/**
 * @description:  java.lang.OutOfMemoryError: Direct buffer memory
 * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 * 元空间本质上和永久代相似,都是JVM方法区概念的具体实现,区别在与元空间不在虚拟机中,而是使用本地内存,所以元空间不指定大小就是受本地内存限制
 * @author: Ding Yawu
 * @create: 2022/4/17 4:04 PM
 */
public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
        System.out.println("配置的maxDirectMemory:" + VM.maxDirectMemory()/1024 / 1024 + "MB");
        try {
            Thread.sleep(2000);
        }catch(Exception e){
            e.printStackTrace();
        }
        //分配在操作系统的本地内存,不属于GC的管辖
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }
}

5. 元空间 OOM

/**
 * @description:  java.lang.OutOfMemoryError: Metaspace
 * -XX:MetaspaceSize=8m
 * @author: Ding Yawu
 * @create: 2022/4/17 5:26 PM
 */
public class metaSpaceOOMTest {
    public static void main(String[] args) {
        int i = 0;
        while (true){
            try {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.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, args);
                    }
                });
                enhancer.create();

            }catch (Throwable e){
                System.out.println("i =" + i);
                e.printStackTrace();
            }
        }
    }
    static class OOMTest{

    }
}

6. 线程过多导致OOM

/**
 * java.lang.OutOfMemoryError:unbale to create new native thread
 *
 * 高并发请求服务器时,经常出现如下异常:java.lang.OutOfMemoryError:unbale to create new native thread
 * 准确的讲该native thread异常与对应的平台有关。
 *
 * 导致原因:
 * 应用创建了太多线程,一个应用进程创建多个线程,超过系统承载极限。
 * 服务器并不允许应用程序创建那么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,如果应用创建超过这个数量,就会报java.lang.OutOfMemoryError:unable to create new native thread
 *
 * 解决办法:
 * 想办法降低应用程序创建线程的数量,分析应用是否真的需要创建那么多线程,如果不是,改代码将线程数降到最低。
 * 对于有的应用,确实需要创建多个线程,远超过linux系统默认的1024个线程的限制,可以通过修改linux服务器配置,扩大linux默认限制。
 */
public class UnableCreateNewThreadDemo {

    public static void main(String[] args) {
        for (int i=1; ;i++){
            System.out.println("******************* i = " +i);

            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },""+i).start();
        }
    }
}

6.1 linux 下的操作

linux下操作 javac -d . UnableCreateNewThreadDemo.java java UnableCreateNewThreadDemo

退不出来了

image.png

登录另外一个客户端 kill -9 pid

6.2 一个进程可以创建多少个线程

可以执行 ulimit -a 这条命令,查看进程创建线程时默认分配的栈空间大小,比如我这台服务器默认分配给线程的栈空间大小为 8M。

image.png 可以修改的 ulimit -s 512

这个目录下可以限制一个用户下的创建线程的数量的限制 image.png

top命令可以查看线程的数量

image.png

我参考的这篇文章:blog.csdn.net/qq_34827674…

我参考的OOM视频 www.bilibili.com/video/BV1Eq…

www.bilibili.com/video/BV11v…