当前位置: 代码迷 >> 综合 >> 深入浅出 Java 虚拟机(七)JVM 内存溢出的几种场景
  详细解决方案

深入浅出 Java 虚拟机(七)JVM 内存溢出的几种场景

热度:90   发布时间:2024-02-01 09:23:15.0

本文章为《深入浅出 Java 虚拟机》系列课程学习笔记,侵删。学习地址为 深入浅出 Java 虚拟机

前言

JVM 在哪个区域会发生内存溢出呢?为什么?如何解决?

堆中发生的 OOM

学过 JVM 的人都知道,堆中分为年轻代跟老年代,我们考虑堆中的 OOM 也从年轻代跟老年代的角度进行考虑。那如果年轻代内存占满,会发生什么呢?其实问题并不大,毕竟年轻代有老年代的担保嘛。但在老年代可就没有这么幸运了,它可没有别的空间进行担保,不得不触发一次 OOM,这是非常严重的后果。

OOM 一般由内存溢出引起,表现在 GC 日志里,一般情况下就是 GC 的时间变长了,而且每次回收的效果都非常一般。GC 后,堆内存的实际占用呈上升趋势。

元空间溢出

在使用堆的时候,我们会给它指定一个大小,但元空间不是。所以如果元空间发生内存溢出会更加严重,会造成操作系统的内存溢出。我们在使用的时候,也会给它设置一个上限。

元空间溢出主要是由于加载的类太多,或者动态生成的类太多。

堆外内存溢出

严格来说,上面的元空间也是属于堆外内存的。但是我们这里的堆外内存指的是 Java 应用程序通过直接方式从操作系统中申请的内存。

在 Java 中我们可以通过相应的 API 去申请直接内存,如果这样做了,通过监控工具,我们能够看到内存占用的明显增长。为了限制这些危险的内存申请,我们可以通过设置相应的参数进行调整。

栈溢出

栈溢出指的就是虚拟机栈的数据太多造成的泄漏,我们可以通过 -Xss 参数设置栈大小。

每个线程都有一个虚拟机栈。线程的开销也是要占用内存的。如果系统中的线程数量过多,那么占用内存的大小也是非常可观的。

如果我们在程序中无休止的进行递归调用,很容易引发栈溢出。

进程异常退出

上面这几种溢出场景,都有明确的原因和报错,排查起来也是非常容易的。但是还有一类应用,死亡的时候,静悄悄的,什么都没留下。

当系统内存不足时,系统会干掉一些进程以求释放一点内存。换句话说,操作系统可能会主动终结 Java 进程。

要解决这种问题,你就不能太贪婪。比如一共 8GB 的机器,你把整整 7.5GB 都分配给了 JVM。当操作系统内存不足时,你的 JVM 就可能成为猎物。

  相关解决方案