OutOfMemoryError
是Java程序中常见的异常,通常出现在内存不足时,导致程序无法运行。
当出现OutOfMemoryError异常时,可能的现象是这样的。
OutOfMemoryError
。异常消息通常会包含一些有关内存分配失败的信息,例如 "Java heap space"(堆空间不足)或 "GC overhead limit exceeded"(垃圾回收开销过大)。可能的堆栈信息是这样的。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at demo.OOMDemo.main(OOMDemo.java:22)
借助MAT工具和内存泄漏产生的dump文件可以分析可能的内存泄漏代码问题定位。
在 Java 中,OutOfMemoryError 是一种错误(Error),而不是异常(Exception)。
它表示 Java 虚拟机(JVM)已经耗尽了可用的内存资源,无法再分配给新的对象,导致程序无法继续执行。
OutOfMemoryError 可能由以下几种情况引起:
在 Java 中,Dump 文件是指在程序发生严重问题(比如崩溃或者出现内存溢出等)时,用于记录当前 JVM 运行状态的文件。Dump 文件可以包含有关 JVM 运行时的诊断信息,例如内存使用情况、线程堆栈信息、对象实例信息等,有助于开发人员分析问题并定位 bug。
通常情况下,Dump 文件主要用于以下几种情况:
生成 Dump 文件通常需要使用 JVM 提供的工具或者命令行参数。例如,可以使用以下 JVM 参数来指定在发生 OutOfMemoryError 时生成 Dump 文件:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.log
生成的 Dump 文件通常是二进制格式的文件,可以使用专门的工具(如 Eclipse Memory Analyzer)来打开和分析。
通过分析 Dump 文件,开发人员可以更好地理解程序的运行情况,并找出问题所在。
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 中进行分析。以下是生成堆转储文件的步骤:
jps
命令查看正在运行的 Java 进程及其 PID。jmap
命令生成堆转储文件。命令格式如下:jmap -dump:file=<文件路径> <PID>
例如,要生成名为 heapdump.hprof
的堆转储文件,可以执行以下命令:
jmap -dump:file=heapdump.hprof <PID>
这将在当前工作目录下生成一个名为 heapdump.hprof
的堆转储文件。
File -> Open Heap Dump
,然后选择生成的堆转储文件。通过这些步骤可以手动生成堆转储文件并使用 MAT 进行分析,即使没有在 OutOfMemoryError 发生时自动生成堆转储文件也可以找到问题所在。
首先通过一段测试代码来模拟OutOfMemoryError异常。
import java.util.ArrayList;
import java.util.List;
/**
* 用于验证oom异常
* jvm启动参数 -Xmx200m -Xms200m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof
*
* @author nine
* @since 1.0
*/
public class OOMDemo {
public static void main(String[] args) {
List<Object> listMock = new ArrayList<>();
List<Object> list = new ArrayList<>();
while (true) {
// 此处代码用于创造oom错误
list.add(new byte[10]);
// 此处代码是干扰代码,因为清空了变量不会内存泄漏
listMock.add(new byte[5]);
listMock.clear();
}
}
}
启动程序运行,增加jvm参数 -Xmx200m -Xms200m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof
。其中堆内存大小为200M,便于复现问题。
等待一段时间后,程序会抛出OutOfMemoryError异常。
java.lang.OutOfMemoryError: Java heap space
Dumping heap to heapdump.hprof ...
Heap dump file created [212763268 bytes in 0.572 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at demo.OOMDemo.main(OOMDemo.java:20)
同时可以在classpath下看到heapdump.hprof
堆转储文件。
打开MAT,选择 File>Open Heap Dump>选择heapdump.hprof>Leak Suspects Report
。
MAT会分析可能的几个问题,标题是 Problem Suspect 1等
。
由于此处只有一段代码,分析出来的问题也就一个可能问题。
The thread java.lang.Thread @ 0xf45310d0 main keeps local variables with total size 204,667,384 (98.35%) bytes.
The memory is accumulated in one instance of “java.lang.Object[]”, loaded by “<system class loader>”, which occupies 204,666,704 (98.35%) bytes.
Significant stack frames and local variables
•demo.OOMDemo.main([Ljava/lang/String;)V (OOMDemo.java:20)◦java.util.ArrayList @ 0xf45930a8 retains 204,666,728 (98.35%) bytes
The stacktrace of this Thread is available. See stacktrace. See stacktrace with involved local variables.
Keywords
java.lang.Object[]
demo.OOMDemo.main([Ljava/lang/String;)V
OOMDemo.java:20
Details »
点击See stacktrace
链接可以看到堆栈信息。
main
at java.lang.OutOfMemoryError.<init>()V (OutOfMemoryError.java:48)
at demo.OOMDemo.main([Ljava/lang/String;)V (OOMDemo.java:20)
这也就是发生异常的代码位置。通过修改第20行代码,将list.add(new byte[10])
注释掉,可以发现oom错误消失。
注:一般堆转储文件很大,可能需要mat的启动参数来进行大文件分析。
# 打开 MemoryAnalyzer.ini 文件
# 修改启动参数为 -Xmx2048m
-startup
plugins/org.eclipse.equinox.launcher_1.6.600.v20231106-1826.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.800.v20231003-1442
-vmargs
--add-exports=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
-Xmx2048m
解决 OutOfMemoryError
异常的方法取决于具体情况和根本原因。
再者可以优化内存参数:
-Xmx
和 -Xms
参数来增加堆内存的最大和初始大小。但需要注意,过大的堆内存可能会导致垃圾回收时间过长,影响程序性能。来自一线全栈程序员nine的探索与实践,持续迭代中。
欢迎关注或者点个小红心~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。