OOM问题模拟及排查

一、模拟问题代码

准备一个空的springboot项目
可以从https://start.spring.io/生成一个(也可以自己创建一个):
在这里插入图片描述
我们准备编写一个由外部访问来触发的OOM,所以依赖里请加入:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

编写触发oom的controller


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class OomController {

    private List<Object> objects = new ArrayList<>();

    @GetMapping("/oom")
    public String triggerOom() {
        while (true) {
            objects.add(new byte[1024 * 1024]); // 每次分配1MB
        }
    }
}

打包

mvn clean package

将生成的jar上传到服务器上

用FileZilla或其他工具

二、部署

为了模拟oom,我们把jvm的内存设置小一点:64M
linux上运行:

nohup java -Xms64m -Xmx64m -jar demo-0.0.1-SNAPSHOT.jar  > output.log 2>&1 &

命令解释:

  • nohup ... & 用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行
  • -Xms64m -Xmx64m是设置初始内存和最大内存为64m
  • > output.log 2>&1 将标准错误 2 重定向到标准输出 &1 ,标准输出 &1 再被重定向输入到 output.log 文件中

如果想直接用IDEA启动,可以在IDEA里设置
在这里插入图片描述
在这里插入图片描述

三、触发OOM

在部署的机器上执行

curl http://localhost:8080/oom

或者通过浏览器远程访问(将server换成服务器ip地址):
http://server:8080/oom

会发现访问报错:

  • curl报错:
{"timestamp":"2024-07-15T06:47:38.083+00:00","status":500,"error":"Internal Server Error","path":"/oom"}
  • 浏览器报错:
    在这里插入图片描述

四、尝试查看日志

  • linux上:
cat output.log

在这里插入图片描述

  • IDEA里:
    在这里插入图片描述

五、dump线程和堆使用情况

  • 获取 JVM 的进程 ID
使用 ps 
ps -ef | grep java
或使用 jps:
jps -l
  • 使用jmap生成堆转储
    <pid>换成上面获取到的pid
jmap -dump:format=b,file=heapdump.hprof <pid>
  • 使用 jstack 生成线程 dump
    <pid>换成上面获取到的pid
jstack -l <pid> > threaddump.txt

六、分析结果

对于oom,主要看堆转储:heapdump.hprof
可以利用Eclipse Memory Analyzer(MAT)来进行分析
Eclipse Memory Analyzer官网下载安装
安装后,打开软件,点击file->Open Heap Dump打开heapdump.hprof,打开时会有如下选项:

在这里插入图片描述
选项解释:

  1. Leak Suspects Report:
    功能:这个选项会生成一个报告,标识出可能的内存泄漏点。MAT会分析堆转储,尝试找出那些可能导致内存泄漏的对象,并生成一个详细的报告。
    用途:用于快速定位和分析可能的内存泄漏问题。报告会显示泄漏的路径、相关对象以及这些对象的内存使用情况。
    推荐使用场景:当你怀疑应用程序中存在内存泄漏,并且想要迅速找到可能的泄漏点时,这个选项非常有用。

  2. Component Report:
    功能:这个选项生成一个组件报告,提供有关内存使用情况的概述和详细的内存分析。它可以按组件(例如类、包等)显示内存使用情况。
    用途:用于全面了解应用程序中的内存使用模式。通过按组件查看内存使用情况,你可以识别哪些部分的代码占用了最多的内存。
    推荐使用场景:当你需要全面分析应用程序的内存使用情况,而不仅仅是查找内存泄漏时,这个选项非常有用。

  3. Re-open previously run reports:
    功能:这个选项允许你重新打开之前生成的报告。MAT会保存你之前生成的报告,因此你可以快速访问和查看这些报告,而无需重新分析堆转储文件。
    用途:用于快速访问之前生成的报告,节省时间和资源,特别是当你需要反复查看和比较多个报告时。
    推荐使用场景:当你已经生成并查看了一些报告,并且想要再次查看或比较这些报告时,这个选项非常有用。

所以,一般选第一个就可以:
在这里插入图片描述
可以看到,下面黄色部分,已经标识出了可能的问题,可以翻到黄色部分最下面,直接点Details进去查看
在这里插入图片描述
在这里插入图片描述

可以看到,这里已经很明显的标明了,时java.lang.Object[]实例占用内存过大,占到了(26214952kb),占总内存的75%

其他功能

当然,你也可以自行选择看不同的视角,点击上面的overview,下面会有不同功能入口:
在这里插入图片描述
解释如下:

  • Actions(动作类):
    • Histogram: Lists number of instances per class(柱状图:列出每个类的实例数)
    • Dominator Tree: List the biggest objects and what they keep alive.(支配者树:列出最大的对象及其存活的依赖)
    • Top Consumers: Print the most expensive objects grouped by class and by package.(顶级消费者:按类和包打印最大的对象)
    • Duplicate Classes: Detect classes loaded by multiple class loaders.(重复类:检测由多个类加载器加载的类)
  • Reports(报告类):
    • Leak Suspects: includes leak suspects and a system overview.(泄漏嫌疑对象:包括泄漏嫌疑对象和系统概述)
    • Top Components: list reports for components bigger than 1 percent of the total heap.(大组件:列出大于总堆1%的组件的报告)
    • Leak Suspects by Snapshot Comparison: includes leak suspects and a system overview from comparing two snapshots.(按快照比较的泄漏嫌疑对象:包括泄漏嫌疑对象和比较两个快照的系统概述)
  • Step By Step(步骤)
    • Component Report: Analyze objects which belong to a common root package or class loader(组件报告:分析属于公共根包或类加载器的对象)

以前两个为例:

  1. Histogram(柱状图:列出每个类的实例数)
    在这里插入图片描述

  2. Dominator Tree(支配者树:列出最大的对象及其存活的依赖)
    可以看到最大的对象是org.springframework.beans.factory.support.DefaultListableBeanFactory @ 0xfc2a3518,最终依赖的对象是java.util.ArrayList @ 0xfc68d618中存储的各个元素:
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值