网站首页 > 技术文章 正文
OutOfMemoryError是JDK中的一个系统错误,注意它是一个Error不是Exception。所以我们常见的catch Exception是无法catch到它的。这个Error几乎每一个Java开发这都有所了解,但是并不是每个人的系统都有机会遇到它,今天我们就来好好分析分析这个OutOfMemoryError,下面的内容肯定有你不知道的!
OOM错误的类关系
上图展示了OutOfMemoryError类的继承关系,可以看到它是从Error继承而来的,而不是从Exception继承的。所以catch Exception是无法catch到OOM异常的。由于Error是继承于Throwable的,所以如果catch Throwable的话是可以catch到OOM错误的(最好不要这么干!!!)。
构造一个OOM错误
要想了解OOM错误,我们就需要先写段代码来抛出这个错误。当要分配内存的时候如果内存不够就会抛出这个错误,下面的代码会往List中不断插入字符串,显然它最终会耗尽所有的内存,从而抛出OOM错误:
有了上面的代码还不是很够,我们还需要限制JVM的可用内存大小,这样运行的时候就快速的抛出异常。所以我们需要在VM启动参数中加入如下参数:
接下来运行这段java代码我们就可以马上得到OOM错误了:
OOM错误和我们的普通的异常有什么不同
从上面的错误信息来看,OOM错误貌似和我们平时遇到的各种Exception并没有太大的不同:
- 都是出现了无法处理的异常情况,然后向上抛出,如果没有catch就一直向上抛知道程序推出
- 他们都记录了错误发生是的堆栈信息(真的吗)
既然OOM作为一个Error独立存在,那么显然它和我们平时常见的Exception肯定是有不同的。首先我把这些不同之处列出来,后面慢慢分析。
- OutOfMemory类并不是等到需要抛异常的时候才被加载到内存。
- 并不是每一个OOM错误都会带上异常堆栈的,也就是说很多OOM错误是不会记录案发现场的。
- 一般的异常都是需要throw的时候new出来的,而OOM是在JVM初始化的时候统一实例化的,后续都是用的最初实例化的哪些OOM对象。
解析来进一步分析
OutOfMemory实例化过程
上面代码就是JVM里启动的时候先创建一批OOM实例的代码,后续的时候如果要抛OOM错误的时候就是直接使用这些实例了。
既然在JVM启动的时候就创建了OutOfMemory对象,那么这个类肯定在JVM启动的时候就已经加载完毕了,后续也不会在出现new的情况了。
为什么有些OOM不会带上案发现场
首先我们看看如下的代码:
这段代码和上面的代码唯一的一点就是catch了Throwable,也就是OOM也能够被catch到。然后我们在看看它的输出:
从上面的输出结果我们可以看出,OOM只有在前4次才会输出调用堆栈信息,后续就没有任何调用堆栈了。
调用堆栈对于OOM错误重不重要?其实并不重要,因为往往引起OOM错误的并不是最终爆出OOM的地方,那个时候只是内存被耗尽了而已,所以对于定位问题并不关键,所以这个堆栈信息就不重要了。
JVM是如何实现OOM错误只有前4次才有调用堆栈的
要想知道原因,还需要再回到前文提到的初始化函数:universe_post_init。它还有一些剩余代码上面没有贴出来:
这段代码会再创建几个OOM对象,个数有是代码里写死的4个。后续当要抛出异常的时候会先看看这个列表里是否还有可用的OOM对象,如果还有就会取出来用,然后组装好相关的错误信息和调用堆栈抛出去。这个列表的对象是一次性的,使用过后就会丢弃的。由于总共只有4个,所以上面的示例代码只有前4次输出了调用堆栈。
OOM错误如何分析解决
上面讲了很多都是OOM实现的基本原理,虽然我们日常工作中比较少见到OOM。但是遇到OOM基本都是需要快速解决的大问题了。
所以我们可以对仅有的一点错误信息进行分析,上面的代码中可以知道不同区域的内存溢出抛出的OOM对象是不一样的,错误信息也是有所不同的,所以我们可以根据这些错误信息分析出是哪个区域内存溢出了。比如上面的示例代码中的:Java heap space表示的就是堆内存溢出了。如果错误信息是:PermGen space表示的就是Perm区溢出了。
确定好出错的区域后就可以根据不同的区域进行不同的操作了,比如比较常见的堆内存溢出就可以dump出内存然后进行分析解决,那就将是另外一大片内容了,这里就不做进一步介绍了。
猜你喜欢
- 2024-10-12 SpringBoot执行jar报错java.lang.OutOfMemoryError_指定内存大小
- 2024-10-12 几种内存溢出(内存溢出类型)
- 2024-10-12 JVM优化:实战OutOfMemoryError异常
- 2024-10-12 JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式
- 2024-10-12 线上故障排查全套路,总有一款适合你
- 2024-10-12 面试被问到“零拷贝”!你真的理解吗?
- 2024-10-12 面试夺命三问之《内存溢出和逃逸分析》
- 2024-10-12 阿里面试官:Exception和Error有什么区别?
- 2024-10-12 Eclipse运行大量文件异常OutOfMemoryError: GC overhead limit
- 2024-10-12 记一次线上内存异常排查实战(线上内存泄漏如何定位)
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)