JVM(四)——OutOfMemoryError 异常

本文深入探讨Java中的OutOfMemoryError异常,解析Java堆、虚拟机栈等区域产生内存溢出的原因及解决方案,帮助开发者理解内存管理和优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



JVM(四)——OutOfMemoryError 异常
  在 Java 运行时的数据区域 中我已经知道了抛出 OutOfMemoryError 异常的区域在 虚拟机栈、本地方法栈、java堆和方法区几个区域。

Java 堆溢出

  Java 堆是创建对象的区域,当GC来不及清除这些对象,并且对象数量达到最大堆的容量限制后就会产生内存溢出异常。

  Java 堆可以自动扩展,如果将 -Xms(堆最小值)和 -Xmx(堆最大值)设置为一样可以避免堆自动扩展。

  Java 堆内存的 OOM 异常是实际应用中常见的内存溢出情况。当 Java 堆出现 OOM 异常时,会提示错误信息:

java.lang.OutOfMemoryError: Java heap sapce复制代码

  值得注意的是,此时异常还分为两种:

  • 内存泄露(Memroy Leak)
      对象本应该被 GC 回收,而未被回收。内存从 GC 中泄露出来。
  • 内存溢出(Memory Overflow)
      对象都还必须存活(JVM会判断),这些对象占的内存超出了Java堆的最大容量。此时最直接的方法就是调大物理内存。

  两者的唯一区别就是,GC没有清除的对象是否是必要的存在的。

虚拟机栈

  由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,所以,-Xoss参数(本地方法栈大小)没有是实际作用。栈容量只由 -Xss 参数设定。

  在虚拟机栈中,存在两种异常:

  • SatckOverflowError
      线程请求的站深度大于虚拟机栈所允许的最大深度
  • OutOfMemoryError
      虚拟机在扩展时无法申请到足够的内存空间(同java堆)

  当在单线程环境中,只会出现 StackOverflowError 异常。切换至多线程后,会出现 OutOfMemoryError 异常。

  看起来,可以通过增大内存空间来缓解或者解决虚拟机栈的 OOM,但是,通过 Java 运行时的数据区域 分析得知:

物理机总内存 = 程序计数器消耗内存 + Xmx(最大 Java堆容量)+ MaxPermSize(最大方法区容量)+ Xss(虚拟机栈容量)+ Xoss(本地栈容量)复制代码

  由于程序计数器消耗内存很小,忽略不计。并且将本地栈容量归为虚拟机栈容量管理的话,那么:

Xss(虚拟机栈容量)= 物理机总内存 -  Xmx(最大 Java堆容量)- MaxPermSize(最大方法区容量)复制代码

  虚拟机栈是线程的“私有内存”,目的是线程分配运行时需要的内存容量,所以有:

Xss(虚拟机栈容量)= 线程数 * 线程栈容量复制代码

  最后得到:

线程数 * 线程栈容量 = 物理机总内存 -  Xmx(最大 Java堆容量)- MaxPermSize(最大方法区容量)复制代码

  在实际情况中,我们希望得到更高的并发量,也就是增大线程数量,此时,有三种方法:

  • 增大物理机总内存
  • 减小java堆内存、方法区容量
  • 减小线程栈容量

  作为开发人员,能做的,也就是后两者。第一条不说申请流程复杂,就算是增加了,那也可能是个无底洞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值