ToB企服应用市场:ToB评测及商务社交产业平台

标题: 一次通过dump文件分析OutOfMemoryError异常代码定位过程 [打印本页]

作者: 王海鱼    时间: 2024-5-19 06:21
标题: 一次通过dump文件分析OutOfMemoryError异常代码定位过程
OutOfMemoryError是Java程序中常见的异常,通常出如今内存不足时,导致程序无法运行。
当出现OutOfMemoryError异常时,大概的征象是如许的。
大概的堆栈信息是如许的。
  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  2.         at demo.OOMDemo.main(OOMDemo.java:22)
复制代码
借助MAT工具和内存泄漏产生的dump文件可以分析大概的内存泄漏代码问题定位。
什么是OutOfMemoryError异常

在 Java 中,OutOfMemoryError 是一种错误(Error),而不是异常(Exception)。
它表示 Java 虚拟机(JVM)已经耗尽了可用的内存资源,无法再分配给新的对象,导致程序无法继续执行。
OutOfMemoryError 大概由以下几种情况引起:
什么是dump文件

在 Java 中,Dump 文件是指在程序发生严重问题(比如崩溃大概出现内存溢出等)时,用于记载当前 JVM 运行状态的文件。Dump 文件可以包罗有关 JVM 运行时的诊断信息,例如内存使用情况、线程堆栈信息、对象实例信息等,有助于开辟人员分析问题并定位 bug。
通常情况下,Dump 文件主要用于以下几种情况:
生成 Dump 文件通常需要使用 JVM 提供的工具大概下令行参数。例如,可以使用以下 JVM 参数来指定在发生 OutOfMemoryError 时生成 Dump 文件:
  1. -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.log
复制代码
生成的 Dump 文件通常是二进制格式的文件,可以使用专门的工具(如 Eclipse Memory Analyzer)来打开和分析。
通太过析 Dump 文件,开辟人员可以更好地理解程序的运行情况,并找出问题所在。
什么是MAT工具

MAT(Memory Analyzer Tool)是一个用于 Java 应用程序内存分析的强大工具。它是一个开源项目,由 Eclipse 基金会提供支持。MAT 的主要功能是资助开辟人员分析 Java 程序的内存使用情况,特别是用于辨认和解决内存泄漏问题。
MAT 工具可以资助开辟人员解决以下范例的问题:
MAT 提供了一个直观的用户界面,可以通过图形化界面举行内存分析和问题定位。它还提供了一系列的分析工具和陈诉,资助开辟人员深入理解 Java 应用程序的内存举动。
搜索引擎搜索 Eclipse Memory Analyzer Tool可以找到下载链接。(外链考核很严格~~)

异常发生了定位异常代码

使用 MAT 定位 OutOfMemoryError(OOM)的过程通常包罗以下步调:
收集堆转储文件:首先,需要在发生 OutOfMemoryError 异常时收集 Java 应用程序的堆转储文件。可以通过在 JVM 启动参数中添加 -XX:+HeapDumpOnOutOfMemoryError 来实现,在发生 OOM 异常时会自动生成堆转储文件。
打开 MAT 工具:打开 Memory Analyzer Tool(MAT)工具,并导入之前收集到的堆转储文件。通常,堆转储文件的格式是 .hprof。
执行内存分析:在 MAT 中,可以执行各种内存分析操纵,以定位导致 OutOfMemoryError 异常的缘故原由。以下是一些常见的分析步调:
定位异常代码:在举行内存分析的过程中,可以尝试定位导致 OutOfMemoryError 异常的相关代码。根据分析结果,可以检察对象的引用关系,确定哪些代码路径导致了内存泄漏大概内存消耗过大的问题。
异常没有发生定位异常代码

异常没有发生定位异常代码,需要通过jmap生成dump文件。
然后将其导入到 MAT 中举行分析。以下是生成堆转储文件的步调:
  1. jmap -dump:file=<文件路径> <PID>
复制代码
例如,要生成名为 heapdump.hprof 的堆转储文件,可以执行以下下令:
  1. jmap -dump:file=heapdump.hprof <PID>
复制代码
这将在当前工作目次下生成一个名为 heapdump.hprof 的堆转储文件。
通过这些步调可以手动生成堆转储文件并使用 MAT 举行分析,即使没有在 OutOfMemoryError 发生时自动生成堆转储文件也可以找到问题所在。
验证demo

首先通过一段测试代码来模拟OutOfMemoryError异常。
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. /**
  4. * 用于验证oom异常
  5. * jvm启动参数  -Xmx200m -Xms200m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof
  6. *
  7. * @author nine
  8. * @since 1.0
  9. */
  10. public class OOMDemo {
  11.     public static void main(String[] args) {
  12.         List<Object> listMock = new ArrayList<>();
  13.         List<Object> list = new ArrayList<>();
  14.         while (true) {
  15.             // 此处代码用于创造oom错误
  16.             list.add(new byte[10]);
  17.             // 此处代码是干扰代码,因为清空了变量不会内存泄漏
  18.             listMock.add(new byte[5]);
  19.             listMock.clear();
  20.         }
  21.     }
  22. }
复制代码
启动程序运行,增加jvm参数 -Xmx200m -Xms200m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof。其中堆内存大小为200M,便于复现问题。
等待一段时间后,程序会抛出OutOfMemoryError异常。
  1. java.lang.OutOfMemoryError: Java heap space
  2. Dumping heap to heapdump.hprof ...
  3. Heap dump file created [212763268 bytes in 0.572 secs]
  4. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  5.         at demo.OOMDemo.main(OOMDemo.java:20)
复制代码
同时可以在classpath下看到heapdump.hprof堆转储文件。
打开MAT,选择 File>Open Heap Dump>选择heapdump.hprof>Leak Suspects Report。
MAT会分析大概的几个问题,标题是 Problem Suspect 1等。

由于此处只有一段代码,分析出来的问题也就一个大概问题。
  1. The thread java.lang.Thread @ 0xf45310d0 main keeps local variables with total size 204,667,384 (98.35%) bytes.
  2. The memory is accumulated in one instance of “java.lang.Object[]”, loaded by “<system class loader>”, which occupies 204,666,704 (98.35%) bytes.
  3. Significant stack frames and local variables
  4. •demo.OOMDemo.main([Ljava/lang/String;)V (OOMDemo.java:20)◦java.util.ArrayList @ 0xf45930a8 retains 204,666,728 (98.35%) bytes
  5. The stacktrace of this Thread is available. See stacktrace. See stacktrace with involved local variables.
  6. Keywords
  7. java.lang.Object[]
  8. demo.OOMDemo.main([Ljava/lang/String;)V
  9. OOMDemo.java:20
  10. Details »
复制代码
点击See stacktrace链接可以看到堆栈信息。
  1. main
  2.   at java.lang.OutOfMemoryError.<init>()V (OutOfMemoryError.java:48)
  3.   at demo.OOMDemo.main([Ljava/lang/String;)V (OOMDemo.java:20)
复制代码
这也就是发生异常的代码位置。通过修改第20行代码,将list.add(new byte[10])注释掉,可以发现oom错误消散。
注:一般堆转储文件很大,大概需要mat的启动参数来举行大文件分析。
  1. # 打开 MemoryAnalyzer.ini 文件
  2. # 修改启动参数为 -Xmx2048m
  3. -startup
  4. plugins/org.eclipse.equinox.launcher_1.6.600.v20231106-1826.jar
  5. --launcher.library
  6. plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.800.v20231003-1442
  7. -vmargs
  8. --add-exports=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
  9. -Xmx2048m
复制代码
发生OutOfMemoryError的解决办法

解决 OutOfMemoryError 异常的方法取决于具体情况和根本缘故原由。
再者可以优化内存参数:
关于作者

来自一线全栈程序员nine的探索与实践,连续迭代中。
接待关注大概点个小红心~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4