Java OOM 内存溢出错误介绍和几种常见异常(附程序实例)

一.Java OOM介绍

Java OOM 内存溢出错误介绍和几种常见异常(附程序实例)_第1张图片
OOM 全称“Out Of Memory”,即“内存用完了”,来源于Java.lang包下的一个类:OutOfMemoryError :

  • OOM属于error。异常Exception和错误Error的区别是:异常能被程序本身可以处理,错误是无法处理。
  • 官方解释:Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector
  • 这个错误会在JVM无法为一个对象分配足够的内存,并且GC收集器无法回收空间时抛出

二.常见异常信息


- java.lang.StackOverflowError

栈空间溢出 ,递归调用卡死,注意这种Error不属于OOM,二者是并列的

实例代码:方法调用自身,不设置返回条件,栈逐渐加深最后报错

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


- java.lang.OutOfMemoryError:Java heap space

堆内存溢出 , 对象过大

实例代码:

public static void main(String[] args) {

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

注意要设置JVM参数,减小堆空间heap space的容量:-Xmx10m -Xms10m



- java.lang.OutOfMemoryError:GC overhead limit exceeded

GC回收时间过长

  • 过长的定义是超过98%的时间用来做GC并且回收了而不倒2%的堆内存
  • 连续多次GC,都回收了不到2%的极端情况下才会抛出
  • 如果不抛出,那就是GC清理的一点内存很快会被再次填满,迫使GC再次执行,这样就恶性循环,cpu使用率一直是100%,二GC却没有任何成果

实例代码

int i = 0;
List<String> list = new ArrayList<>();
try{
    while(true){
        list.add(String.valueOf(++i).intern());
    }
}catch(Throwable e){
    System.out.println("********");
    e.printStackTrace();
    throw e;
}

需设置参数 : -MaxDirectMemorySize=5m



- java.lang.OutOfMemoryError:Direct buffer memory

执行内存挂了

  • 写NIO程序经常使用ByteBuffer来读取或写入数据,这是一种基于通道(Channel)与缓存区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了在java堆和native堆中来回复制数据
  • ByteBuffer.allocate(capability) 第一种方式是分配JVM堆内存,属于GC管辖,由于需要拷贝所以速度较慢
  • ByteBuffer.alloctedDirect(capability)分配os本地内存,不属于GC管辖,不需要拷贝,速度较快

但如果不断分配本地内存,堆内存很少使用,那么jvm就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存救护i出现oom,程序崩溃


- java.lang.OutOfMemoryError:unable to create new native thread好案例

  • 应用创建了太多线程,一个应用进程创建了多个线程,超过系统承载极限
  • 你的服务器并不允许你的应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024,超过这个数量,就会报错

解决办法

  • 降低应用程序创建线程的数量,分析应用给是否针对需要这么多线程,如果不是,减到最低
  • 修改linux服务器配置


- java.lang.OutOfMemoryError:Metaspace

元空间主要存放了虚拟机加载的类的信息、常量池、静态变量、即时编译后的代码

你可能感兴趣的:(JVM)