《深入理解 Java 虚拟机》学习笔记 Day6(OutOfMemoryError 异常实战:Java 堆溢出)

学习内容:第2章 - Java 内存区域与内存溢出异常

实战代码均在我的 Git 仓库中:https://github.com/nx-xn2002/JVM-Learn.git

环境准备

书中使用的是 Eclipse,我使用的是我个人更常用的的 IDEA,JDK 版本是 JDK 19。实战中通过以下方式来设置调试过程中的虚拟机启动参数(VM options):

  1. 在程序调试启动处选择Edit...
    在这里插入图片描述
  2. 在窗口中VM options 处填入启动参数
    在这里插入图片描述

实战

Java 堆溢出

Java 堆用于存储对象实例,所以只要我们不断创建新对象,并保证 GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,随着对象数量增加,总容量触及到堆的最大容量限制后,就会产生内存溢出异常。

/**
 * Java 堆溢出
 * VM Options:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 *
 * @author Ni Xiang
 */
public class HeapOutOfMemory {
    static class OutOfMemoryObject {
    }

    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        while (true) {
            list.add(new OutOfMemoryObject());
        }
    }
}

以下代码中,我使用死循环不断创建 OutOfMemoryObject 对象,同时,在启动时,设置了参数-Xms20m -Xmx20m 限制 Java 堆的大小为 20 MB,且不可扩展(将堆的最小值 -Xms 参数与最大值 -Xmx 参数设置为一样可以避免堆自动扩展),然后通过参数 -XX:+HeapDumpOnOutOfMemoryError 让虚拟机在出现溢出异常时 Dump 出当前内存堆转储快照来进行事后分析。

运行结果如下图:
在这里插入图片描述
出现 Java 堆内存溢出时,异常堆栈信息 java.lang.OutOfMemoryError 会进一步提示 Java heap space。要解决这个问题,最常规的处理方法就是对 Dump 出来的堆转储快照进行分析。

如下图就是用 IDEA 打开快照文件:
在这里插入图片描述
展开可以发现,就是海量的 OutOfMemoryObject 占据了大量的 Java 堆内存
在这里插入图片描述

分析的第一步是确认内存中导致 OOM 的对象是否是必要的,也就是要先分清楚是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)

内存泄漏(Memory Leak)

是指在程序运行过程中,动态分配的堆内存未被正确释放,导致系统内存浪费,进而可能引起程序运行速度减慢甚至系统崩溃的问题。如果内存中导致 OOM 的对象是非必要的,则可以初步判断是内存泄漏问题

内存溢出(Memory Overflow)

存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。如果内存中导致 OOM 的对象是必要的,则可以初步判断是内存溢出问题

作者针对这两种情况,给出了进一步的分析解决思路:

  • 内存泄漏:

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象是通过怎样的引用路径、与哪些GC Roots相关联,才导致垃圾收集器无法回收它们,根据泄漏对象的类型信息以及它到GC Roots引用链的信息,一般可以比较准确地定位到这些对象创建的位置,进而找出产生内存泄漏的代码的具体位置。

  • 内存溢出:

如果不是内存泄漏,换句话说就是内存中的对象确实都是必须存活的,那就应当检查Java虚拟机的堆参数(-Xmx与-Xms)设置,与机器的内存对比,看看是否还有向上调整的空间。再从代码上检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况,尽量减少程序运行期的内存消耗。

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值