JAVA 内存区域-内存溢出介绍

JVM-运行时数据区域存在的内存溢出的情况解析

Posted by Admin on February 8, 2020

内存溢出(OutOfMemoryError)

内存溢出通常指程序在申请内存时,没有足够的内存空间供其使用,出现了Out Of Memory。在java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运动时区域都有发生OutOfMemoryError异常的可能。

区域解析

1. Java堆溢出:

  • Java堆内存的OOM异常是实际应用中常见的内存溢出异常情况,最常见的可能导致 OOM 的原因就是内存泄漏,当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space
  • 可以通过内存映像分析工具(Memory Analyzer)对Dump出来的堆转储快照进行分析,分析时内存泄漏(通过工具查看泄漏对象到GC Roots的引用链)还是内存溢出(检查虚拟机的堆参数(-Xmx与-Xms))

2. JVM虚拟机栈和本地方法栈溢出:

  • 栈容量只由-Xss参数设定
  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
  • 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
  • 当我们写一个递归方法,这个递归方法没有循环终止条件,最终会导致 StackOverflowError 的错误。当然,如果栈空间扩展失败,也是会发生 OOM 的。
  • 程序计数器,虚拟机栈,本地方法栈 三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不絮地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知,因此这几个区域的内存分配和回收都具备确定性。

3. 方法区和运行时常量池溢出:

  • 方法区用于存放class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。对于这些区域的测试,基本的思路是运行时产生大量的类区填满方法区,直到溢出。
  • 方法区现在基本上不太会发生 OOM,但在早期内存中加载的类信息过多的情况下也是会发生 OOM 的。

4. 本机直接内存溢出:

  • 本机直接内存的分配不会受到Java堆大小的限制,但是会受到本机总内存(包括RAM以及SWAP区或者分页文件)大小以及处理器寻址空间的限制。服务器管理员在配置虚拟机参数时,会根据实际内存设置-Xmx等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展时出现OOM异常。