简述 OutOfMemoryError

在日常开发中,我们多多少少都会遇到 OutOfMemoryError(内存溢出)的 Error 异常,简单来说就是内存不够用了。可是 OutOfMemoryError 具体是怎么一回事?什么原因会导致这个异常的发生?

如何加载 OutOfMemoryError

OutOfMemoryError 在 JVM 启动的时候就已经被加载,可以通过下面这个命令,打印出虚拟机装入的类的信息。

java -verbose:class -version
图1
图1

根据图1的结果,JVM 启动过程中加载了 OutOfMemoryError 类。同时,创建了几个 OutOfMemoryError 对象,每个 OutOfMemoryError 对象代表了一种内存溢出的场景,例如:

java.lang.OutOfMemoryError: Java heap space

◉ 创建新的对象时, 堆内存中的空间不足以存放新创建的对象

◉ 堆内存使用量达到最大内存限制

java.lang.OutOfMemoryError: Metaspace

◉ Metaspace(元数据区)已被占满,主要原因是加载到内存中的 class 数量太多或者体积太大。

java.lang.OutOfMemoryError: GC overhead limit exceeded

◉ 连续多次 GC 回收效率太低,默认情况下, 如果GC花费的时间超过98%, 并且 GC 回收的内存少于2%,JVM就会抛出这个错误。

java.lang.OutOfMemoryError: Out of swap space

◉ 虚拟内存不足。

java.lang.OutOfMemoryError: Unable to create new native thread

◉ 操作系统的虚拟内存已耗尽,或者线程数超过了操作系统的限制,因此操作系统创建新的 native thread 失败。

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

◉ 创建的数组长度超过限制。

OutOfMemoryError 的数量

根据 PreallocatedOutOfMemoryErrorCount 这个参数可以设定创建 OutOfMemoryError 的数量。不过,参数只能在 debug 版本可以被设置,通常我们使用的 release 版本不能自定义设置。

PreallocatedOutOfMemoryErrorCount 的默认值为4,具体来源可以参考以下网址。

https://stas-blogspot.blogspot.com/2011/07/most-complete-list-of-xx-options-for.html

从 universe_post_init() 方法可以看到,OutOfMemoryError 类在 JVM 启动的时候就根据 PreallocatedOutOfMemoryErrorCount 参数加载固定数量的 OutOfMemoryError 类。

// 在JVM主要组件都初始化完成后,编译器调用的方法
bool universe_post_init() {
  // ……
  int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
  Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false);
  for (int i=0; i<len; i++) {
    oop err = k_h->allocate_instance(CHECK_false);
    Handle err_h = Handle(THREAD, err);
    java_lang_Throwable::allocate_backtrace(err_h, CHECK_false);
    Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h());
  }
  // ……
}

怎么抛出 OutOfMemoryError

抛出 OutOfMemoryError 异常,必然是发生在内存分配的时候,例如创建对象的时候需要分配内存空间,新对象存放在 Eden区。

抛出异常的具体流程如下:

如果 Eden区 内存空间不足,或者对象比较大以至于老年区也分配失败,那么就会触发 Young GC。

如果 Young GC 后 Eden区 仍旧没有足够的内存空间进行分配,那么就会触发 Old GC。

如果 Full GC 后 Eden区 和 老年区 仍旧没有足够的内存空间进行分配,那么就会抛出 OutOfMemoryError 异常。

具体流程如下图所示:

图2
图2

再说几句

OutOfMemoryError 就是一个比较常见的异常,然而,往往这么常见的异常我们只知其然,而不知其所以然。永远保持一颗探索的好奇心,你将发现世界原来是这么深邃。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值