042-堆内存放不下造成内存溢出

105次阅读
没有评论

共计 1639 个字符,预计需要花费 5 分钟才能阅读完成。

对象太多了!堆内存实在是放不下,只能内存溢出!

1、前文回顾

之前的文章已经分析了Metaspace和栈内存两块内存区域发生内存溢出的原理,同时给出了一些较为常见的引发他们内存溢出的场景,一般只要代码上注意一些,不太容易引发那两块区域的内存溢出。

真正最容易引发内存溢出的,说白了就是平时我们系统创建出来的对象实在是太多了,最终就导致了系统的内存溢出!

2、从对象在Eden区分配开始讲起

如果要把这大量的对象是如何导致堆内存溢出的给讲清楚,那就得从系统运行,在Eden区创建对象开始讲起了。

咱们都知道,平时系统运行的时候一直不停的创建对象,然后大量的对象会填满Eden区

一旦Eden区满之后,就会触发一次Young GC,然后存活对象进入S区。

如下图所示

042-堆内存放不下造成内存溢出042-堆内存放不下造成内存溢出

3、高并发场景下导致ygc后存活对象太多

当然因为各种各样的情况,一旦出现了高并发场景,导致ygc后很多请求还没处理完毕,存活对象太多,可能就在Survivor区域放不下了,此时就只能进入到老年代里去了,老年代很快就会放满了,如下图所示。

042-堆内存放不下造成内存溢出

一旦老年代放满了就会触发Full GC,如下图所示。

042-堆内存放不下造成内存溢出

我们假设ygc过后有一批存活对象,Survivor放不了,此时就等着要进入老年代里,然后老年代也满了,那么就得等着老年代进行CMS GC,必须回收掉一批对象,才能让年轻代里存活下来的一批对象进去。

但是呢,不幸的事情发生了,老年代GC过后,依然存活下来了很多的对象!如下图所示。

042-堆内存放不下造成内存溢出

这个时候如果年轻代还有一批对象等着放进老年代,人家GC过后空间还是不足怎么办?

还能怎么办!只能是内存溢出了!如下图所示!

042-堆内存放不下造成内存溢出

所以这个时候,老年代都已经塞满了,你还要往里面放东西,而且触发了Full GC回收了老年代还是没有足够内存空间,你坚持要放?那只能给你一个内存溢出的异常了!JVM跑不动了,崩溃掉。

这个就是典型的堆内存实在放不下过多对象的内存溢出的一个典型范例。

4、什么时候会发生堆内存的溢出?

发生堆内存溢出的原因其实总结下来,就一句话:

有限的内存中放了过多的对象,而且大多数都是存活的,此时即使GC过后还是大部分都存活,所以要继续放入更多对象已经不可能了,此时只能引发内存溢出问题。

所以一般来说发生内存溢出有两种主要的场景:

  1. 系统承载高并发请求,因为请求量过大,导致大量对象都是存活的,所以要继续放入新的对象实在是不行了,此时就会引发OOM系统崩溃

  2. 系统有内存泄漏的问题,就是莫名其妙弄了很多的对象,结果对象都是存活的,没有及时取消对他们的引用,导致触发GC还是无法回收,此时只能引发内存溢出,因为内存实在放不下更多对象了

因此总结起来,一般引发OOM,要不然是系统负载过高,要不然就是有内存泄漏的问题

这个OOM问题,一旦你的代码写的不太好,或者设计有缺陷,还是比较容易引发的,所以这个问题也是我们后面要重点分析的。

正文完
 
yangleduo
版权声明:本站原创文章,由 yangleduo 2023-05-12发表,共计1639字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。