ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java.lang.OutOfMemoryError——java oom总结!

2021-06-04 16:53:04  阅读:159  来源: 互联网

标签:lang java class GC 内存 OutOfMemoryError import public


    一般你去面试的时候,面试官经常会问:请谈谈你对OOM的认识?然后,你可能会说OOM就是out of memory,那如果你只是这么答的话,这可不是面试官想要的答案;面试官又接着问,那你生产过程中有遇到哪些OOM呢?请你说说出常见的OOM问题?这时的你可能是懵的。你知道几种常见的OOM呢?欢迎评论区留言。

  常见的OOM总述:

  

 1. StackOverflowError

    线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常 。递归调用方法,如果没有方法出口的方法会造成StackOverflowError,或者说如果调用的过深都会抛出,这种错误也比较容易定位。

public class StackOverflowErrorDemo {
    public static void main(String[] args){
        stackOverflowError();
    }

    private static void stackOverflowError() {
        stackOverflowError();
    }
}

2. java.lang.OutOfMemoryError: Java heap space 

    溢出原因:深入理解Java虚拟机书中讲到java堆溢出,Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

import java.util.Random;

public class JavaHeapSpaceDemo {
    public static void main(String[] args){
        String str = "seu";

        while(true){
            str += str + new Random().nextInt(11111111)+new Random().nextInt(22222222);
            str.intern();
        }

    }
}

3. java.lang.OutOfMemoryError:GC overhead limit exceeded

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

/*
* GC回收时间长时会抛出OutOfMemoryError。过长的定义是,超过98%的时间用来做GC并且回收了
* 不到2%的堆内存,连续多次GC都只回收了不到2%的极端情况下才会抛出。

假设不抛出GC overhead limit错误会发生什么情况呢?
那就是GC清理的这么点内存很快会再次填满,迫使GC再次执行,这样就形成恶性循环,CPU使用率一直
是100%,而GC缺没有任何成果。
* */

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();
            throw e;
        }

    }
}

4. java.lang.OutOfMemoryError:Direct buffer memory

import java.nio.ByteBuffer;

/**
 * 配置参数: -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 * 导致原因:
 *  写NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道,缓冲区的IO方式
 *   ByteBuffer.alloction(capabicity)分配jvm堆内存,属于GC管辖范围
 *   ByteBuffer.allocateDirect(capabicity)分配本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度较快。
 *   如果不断分配本地内存,但是堆内存很少使用,那么jvm不需要执行GC,DirectByteBuffer对象就不会被回收,这时候堆内存充足
 *   但是本地内存已经使用光了,再次分配的时候就会出现OOM异常!
 *   --堆内存不够的时候,会触发fullGC顺带回收 DirectMemory!
 *   MaxDirectMemorySize 默认是64M
 */
public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
        System.out.println("配置的MaxDirectMemory:"+(sun.misc.VM.maxDirectMemory()/(double)1024/1024)+"MB");
        try{Thread.sleep(3000);} catch (InterruptedException e) { e.printStackTrace();}

        //-XX:MaxDirectMemorySize=5m 我们配置为5M 但是实际使用是6M
        ByteBuffer.allocateDirect(6*1024*1024);
    }
}

5. java.lang.OutOfMemoryError:unable to create new native thread

     不知道你们生产环境是否会出现这种情况,高并发请求服务器时,经常出现如下异常java.lang.OutOfMemoryError:unable to create new native thread。那出现的原因呢?

    1.创建太多的线程了

    2.服务器的设置限制了你创建线程的数量了(linux 允许创建的线程数是1024个)

6. java.langOutOfMemoryError:Metaspace

    我们知道Java8及以后已经使用Metaspace来替代永久代,Metaspace并不在虚拟机内存中而是使用本地内存。主要还是是加载到内存中的 class 数量太多或者体积太大。这时可以通过JVM参数-XX:MaxMetaspaceSize指定。

* JVM参数: -XX:MetaspaceSize=8m  -XX:MaxMetaspaceSize=8m
 * Java8之后的版本使用Metaspace来替代永久代
 * Metaspace是方法区在HotSpot中的实现,它与持久带最大的区别在于:Metaspace并不在虚拟机内存中而是使用
 * 本地内存,也即在java8中,class metaspace(the virtual machines internal presentation of java class)
 * ,被存储在叫做Metaspace的native memory
 *
 * 永久代(Metaspace)存放以下信息:
 * 虚拟机加载的类信息
 * 常量池
 * 静态变量
 * 即时编译后的代码
 * */

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MetaspaceOOMT {
    static class OOMTest {

    }

    public static void main(String[] args) {
        int i = 0;//模拟多少次后发生异常

        try {
            while (true) {
                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);
            e.printStackTrace();
        }
    }
}

总结

 理解jvm才能更有深度的理解这些异常,对jvm的学习应该贯穿整个java!欢迎关注我的公众号,一起学习!

                            

                    关注「Java源码进阶」,获取海量java,大数据,机器学习资料!

标签:lang,java,class,GC,内存,OutOfMemoryError,import,public
来源: https://blog.51cto.com/u_15257216/2861469

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有