常见OOM异常

堆溢出

当报错信息java.lang.OutOfMemoryError后面带有java heap space时,说明是java堆溢出。
  • 1

由于Heap是用来存放实例的,堆溢出,也就说明了当前的实例对象过多,而且这些对象一直处于存活状态(JVM判断对象是否存活,是通过判断GC Roots和对象之间的是否存在可达路径)。出现这种问题,一般要考虑下列两种情况:

  • 内存泄露:

一般出现这种情形,需要判断是否是内存泄露,即一些无用对象一直被引用,导致GC无法有效回收它,这时可以通过一些工具,查看Heap dump,看看GC roots到对象之间的引用链,定位到泄露的对象。

  • 内存溢出:

另一种情形就是内存溢出,也就是这些对象的确是需要存活的,因此也就不存在GC回收异常。一般这种情况,可能是对象过大,或者对象的生命周期过长,需要从业务层面,减少这些对象在运行期的内存消耗。
另外一种情形,也有可能是我们的堆分配的内存过小,可以通过配置堆的参数(-Xmx最大内存与-Xms 最小内存)来设置

栈溢出

栈溢出需要建立两个概念,一个就是整个java stack区域的大小,一个就是单个线程中stack的大小。

整个stack区的大小是由jvm的内存容量- heap容量 - 方法区容量 确定的,是一个固定的值。
单个线程中 stack的大小也是固定的,可以通过 -Xss 配置

StackOverflowError,线程请求的栈的深度超过虚拟机允许的最大深度。

每个线程中stack的容量是固定,由于stack是用于存放各个方法的内部变量表的,所以,当大量的方法被调用,而又未及时结束,或者单个方法内部定义了大量局部变量,使单个栈帧很大,这样使得占用的空间超过了单个线程中stack的深度,因此会报这个异常。

OutOfMemoryError 虚拟机扩展栈时无法分配足够的内存空间

一般情况下,当启用一个线程时,就会给这个线程分配一个固定大小的stack,由于整个java stack区的大小是有限的,当我们的线程过多时,就会抛出OutOfMemoryError异常。由此可见,单个线程stack的大小并非越大越好,因为这与我们的线程数息息相关。

方法区溢出
方法区是用于存放类的定义Class文件和常量池等,由此可见,当类或者常量池过多时,会造成方法区溢出

当报错信息java.lang.OutOfMemoryError后面带有PremGen space时,说明是方法区溢出。
  • 1

当前的一些框架,如Spring、Hibernate等,会使用CGlib技术对类进行增强,相应地会增加类的大小;
还有一些应用,会动态生成JSP文件,JSP文件是需要编译成Class文件的,大量的文件也有溢出的可能;
或者开发代码中往常量池添加过多的常量,也有可能造成常量池溢出。
另外一种可能就是我们的应用本身的类就太多,而方法区设置的容量不足,也会容易溢出。
设置方法区的大小,可通过配置-XX:PremSize 设置最小值,-XX:MaxPremSize设置最大值。

 楼主最近看到OOM异常,于是上网搜索找到了这一篇写的通俗易懂的博客,现在分享给大家:
 博客转载于:https://blog.csdn.net/qq_33450379/article/details/53731318

猜你喜欢

转载自blog.csdn.net/qq_32575047/article/details/81232328
今日推荐