troubleshoot之:分析OutOfMemoryError异常
简介
java.lang.OutOfMemoryError应该java应用程序中非常常见的一个的错误了。
那么OutOfMemoryError产生的原因是什么呢?我们怎么去查找相应的错误呢?一起来看看吧。
OutOfMemoryError
先看一下OutOfMemoryError的定义,OutOfMemoryError继承自
VirtualMachineError,它是Error的一种,表示的是应用程序无法处理的异常,一般情况下会导致虚拟机退出。
public class OutOfMemoryError extends VirtualMachineError { @java.io.Serial private static final long serialVersionUID = 8228564086184010517L; /** * Constructs an {@code OutOfMemoryError} with no detail message. */ public OutOfMemoryError() { super(); } /** * Constructs an {@code OutOfMemoryError} with the specified * detail message. * * @param s the detail message. */ public OutOfMemoryError(String s) { super(s); } }
一般情形下,如果heap没有更多的空间来分配对象,就会抛出OutOfMemoryError。
还有一种情况是没有足够的native memory来加载java class。
在极少数情况下,如果花费大量时间进行垃圾回收并且只释放了很少的内存,也有可能引发java.lang.OutOfMemoryError。
如果发生OutOfMemoryError,同时会输出相应的stack trace信息。
下面我们分析一下各个不同的OutOfMemoryError。
java.lang.OutOfMemoryError: Java heap space
Java heap space表示的是新对象不能在java heap中分配。
如果遇到这种问题,第一个要想到的解决方法就是去看配置的heap大小是不是太小了。
当然,如果是一个一直都在运行的程序,突然间发生这种问题就要警惕了。因为有可能会存在潜在的内存泄露。需要进一步分析。
还有一种情况,如果java对象实现了finalize方法,那么该对象在垃圾回收的时候并不会立刻被回收。而是放到一个finalization队列中。
这个队列会由终结器守护线程来执行。如果终结器守护线程的执行速度比对象放入终结器队列中的速度要慢的话,就会导致java对象不能被及时回收。
如果应用程序创建了高优先级的线程,那么高优先级的线程将有可能会导致对象被放入finalization队列的速度比终结器守护线程的处理速度慢。
java.lang.OutOfMemoryError: GC Overhead limit exceeded
GC overhead limit exceeded表示的是GC一直都在运行,从而导致java程序本身执行非常慢。
如果一个java程序98%的时间都在做GC操作,但是只恢复了2%的heap空间,并且持续5次。那么java.lang.OutOfMemoryError将会被抛出。
可以使用下面的参数来关闭这个功能。
-XX:-UseGCOverheadLimit
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
这个错误的意思是,要分配的array比heap size大。
比如说设置的最大heap大小是256M,但是分配了一个300M的数组,就会出现这个问题。
java.lang.OutOfMemoryError: Metaspace
从JDK8之后,Metaspace已经移到了java的本地内存空间中。如果Metaspace超出了限制的大小,那么java.lang.OutOfMemoryError也会抛出。
Metaspace的空间大小可以通过MaxMetaSpaceSize来设置。
java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?
当本地堆分配失败并且本地堆即将耗尽的时候就会报这个异常。
java.lang.OutOfMemoryError: Compressed class space
在64位的平台,对象指针可以用32位表示(对象指针压缩)。
对象指针压缩可以通过:
UseCompressedClassPointers
来启用,默认这个参数是开启的。
我们可以使用CompressedClassSpaceSize来设置指针压缩空间的大小。
注意,只有klass元信息是存放在CompressedClassSpaceSize设置的空间中的,而其他的元信息都是存放在Metaspace中的。
OutOfMemoryError: reason stack_trace_with_native_method
这个错误表示本地方法遇到分配失败。
遇到这种问题可能需要操作系统的本地调试工具来解决。
总结
本文介绍了OutOfMemoryError的不同种类,希望大家能够有所收获。
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/jvm-outofmemoryerror-analysis/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
troubleshoot之:使用JFR解决内存泄露
简介 虽然java有自动化的GC,但是还会有内存泄露的情况。当然java中的内存泄露跟C++中的泄露不同。 在C++中所有被分配的内存对象都需要要程序员手动释放。但是在java中并不需要这个过程,一切都是由GC来自动完成的。那么是不是java中就没有内存泄露了呢? 要回答这个问题我们首先需要界定一下什么是内存泄露。如果说有时候我们不再使用的对象却不能被GC释放的话,那么就可以说发生了内存泄露。 内存泄露的主要原因就是java中的对象生命周期有长有短。如果长生命周期的对象引用了短生命周期的对象,就有可能造成事实上的内存泄露。 一个内存泄露的例子 我们举一个内存泄露的例子,先定义一个大对象: public class KeyObject { List<String> list = new ArrayList<>(200); } 然后使用它: public class TestMemoryLeak { public static HashSet<Object> hashSet= new HashSet(); public static void main(...
- 下一篇
2.3.1 理解动态代理 -《SSM深入解析与项目实战》
2.3 动态代理 Spring中AOP的拦截功能就是使用Java中的动态代理实现的。也就是在被代理类(方法)的基础上增加切面逻辑,生成代理类(方法)。切面的逻辑可以在目标类函数执行之前或者执行之后,或者在目标函数抛出异常的时候执行,则需要重写不同的方法。在本节中对于Spring中的AOP不进行过多的讲解。接下来详细讲解Java中的动态代理。 2.3.1 理解动态代理 为了更方便读者理解,在介绍之前,先介绍一下几个本文关于代理的名词。 委托类 - 被代理的类(也可以叫目标类) 代理类 - 进行代理的类 消费类 - 调用代理类的类 在理解动态代理之前,我想给大家介绍一下静态代理。很容易理解,静态,也就是代理类在程序运行之前就已经确定的,那么对该类进行代理的方式,即可称为静态代理。 一般情况下,静态代理中的代理类和委托类都会继承相同的父类或者实现相同的接口。 更多内容请查看原文地址: https://chenhx.blog.csdn.net/article/details/107964007
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Hadoop3单机部署,实现最简伪集群
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作