使用MAT分析OOM问题

这篇具有很好参考价值的文章主要介绍了使用MAT分析OOM问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

OOM和内存泄漏在我们的工作中,算是相对比较容易出现的问题,一旦出现了这个问题,我们就需要对堆进行分析。

一般情况下,我们生产应用都会设置这样的JVM参数,以便在出现OOM时,可以dump出堆内存文件,也就是保留案发现场,方便我们后续的研究。

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=.

至于分析堆内存的工具可以使用Jvisualvm,但Jvisualvm只能查看类使用内存的直方图,无法有效的追踪内存的引用关系,因此更加推荐使用Eclipse 的 Memory Analyzer(也叫做 MAT)做堆转储的分析。可以通过这个链接,下载 MAT。

使用MAT分析OOM问题,一般可以按照以下的思路进行:

  1. 通过支配树功能或直方图功能查看消耗内存最大的类型,来分析内存泄露的大概原因;
  2. 查看那些消耗内存最大的类型、详细的对象明细列表,以及它们的引用链,来定位内存泄露的具体点;
  3. 配合查看对象属性的功能,可以脱离源码看到对象的各种属性的值和依赖关系,帮助我们理清程序逻辑和参数;
  4. 辅助使用查看线程栈来看 OOM 问题是否和过多线程有关,甚至可以在线程栈看到 OOM 最后一刻出现异常的线程。

接下来,我们有一个案例,通过这个案例可以得到一个OOM后的堆转储文件java_pid12300.hprof,然后我们通过MAT的直方图、支配树、线程栈、OQL 等功能来分析此次 OOM 的原因。

在文章的最后会有代码地址,运行代码一段时间发生OOM后,你就可以得到一个hprof文件。

1、查看堆概述信息

通过MAT打开java_pid12300.hprof文件后,首先进入的是概览信息界面。
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
从这个概览图中,我们可以看出整个堆的大小是437.6MB。接下来我们可以通过直方图来看这437.6MB的对象都是哪些对象。

2、直方图观察对象分布

点击工具栏的第二个图标,进入到直方图视图
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
从直方图中,我们可以看到,char[]字节数组占用的内存最多,对象数量给也最多。排名第二的String对象也很多,可以推断程序可能是被String占满了(String底层使用的就是char[]作为实际存储,因此String多,char[]也会多)

3、分析char[]的引用关系

在 char[]上点击右键,选择 List objects->with incoming references,可以列出所有的char[]实例,以及每个 char[]的整个引用关系链:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
随机展开一个 char[],如下图所示:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查

  • 在①处看到,这些 char[]几乎都是 10000 个字符、占用 20000 字节左右(char 是 UTF-16,每一个字符占用 2 字节);
  • 在②处看到,char[]被 String 的 value 字段引用,说明 char[]来自字符串;
  • 在③处看到,String 被 ArrayList 的 elementData 字段引用,说明这些字符串加入了一个 ArrayList 中;
  • 在④处看到,ArrayList 又被 FooService 的 data 字段引用,这个 ArrayList 整个 RetainedHeap 列的值是 431MB。

Retained Heap(深堆)代表对象本身和对象关联的对象占用的内存,Shallow Heap(浅堆)代表对象本身占用的内存。比如,我们的 FooService 中的 data 这个 ArrayList 对象本身只有 16 字节,但是其所有关联的对象占用了 431MB 内存。这些就可以说明,肯定有哪里在不断向这个 List 中添加 String 数据,导致了 OOM。

左侧的蓝色框可以查看每一个实例的内部属性,图中显示 FooService 有一个 data 属性,类型是 ArrayList。

如果我们希望看到字符串完整内容的话,可以右键选择 Copy->Value,把值复制到剪贴板或保存到文件中:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
这里,我们复制出的是 10000 个字符 a(下图红色部分可以看到)。对于真实案例,查看大字符串、大数据的实际内容对于识别数据来源,有很大意义:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查

4、利用支配树查看内存中最大的对象

点击工具栏的第三个按钮可以进入到支配树界面,这个界面会根据Retained Heap 倒序直接列出占用内存最大的对象。
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
这样我们就可以很快速的定位到是哪个对象导致的OOM,接下来我们就要看一下OOM的时候,FooService在执行什么逻辑。

5、查看线程视图

点击工具栏的第五个按钮,打开线程视图,首先看到的是main线程。
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
从黑色框来看,确实这里发生了OOM。紧接继续往下看,寻找我们可以的FooService,可以看到这个线程栈中FooSerice.oom()方法被调用。

在往下看的话,可看到参数中的 CommandLineRunner 你应该能想到,OOMApplication 其实是实现了 CommandLineRunner 接口,所以是 SpringBoot 应用程序启动后执行的。

在FooService.oom()往上看,红色框部分,我们可以猜测出这些字符串是由Stream操作产生的,以及在上面的StringBuilder 的 append是最终导致OOM的方法。

6、OQL查找类

最后我们还可以看一下FooService是不是Spring的Bean,又是不是单例?如果是的话,就更能确定是因为反复调用同一个 FooService 的 oom 方法,然后导致其内部的 ArrayList 不断增加数据的。

我们可以点击工具栏的第四个按钮,进入到OQL界面,然后在这里我们可以使用类似 SQL 的语法,在 dump 中搜索数据(你可以直接在 MAT 帮助菜单搜索 OQL Syntax,来查看 OQL 的详细语法)。

比如,输入如下语句搜索 FooService 的实例:

select * from fcp.troubleshootingtools.mat.FooService

可以看到只有一个实例,然后我们通过 List objects 功能搜索引用 FooService 的对象:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
得到以下结果:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查可以看到,一共两处引用:

  • 第一处是,OOMApplication 使用了 FooService,这个我们已经知道了。
  • 第二处是一个 ConcurrentHashMap。可以看到,这个 HashMap 是 DefaultListableBeanFactory 的 singletonObjects 字段,可以证实 FooService 是 Spring 容器管理的单例的 Bean。

我们甚至可以在HashMap 上点击右键,选择 Java Collections->Hash Entries 功能,来查看其内容:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
我们还可以在Value列通过正则进一步对解决进行过滤筛选:
使用MAT分析OOM问题,JVM,问题排查,java,jvm,MAT,问题排查
到现在为止,我们虽然没看程序代码,但是已经大概知道程序出现 OOM 的原因和大概的调用栈了。我们再贴出程序来对比一下,果然和我们看到得一模一样:

@SpringBootApplication
public class OOMApplication implements CommandLineRunner {
    @Autowired
    FooService fooService;
    public static void main(String[] args) {
        SpringApplication.run(OOMApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        //程序启动后,不断调用Fooservice.oom()方法
        while (true) {
            fooService.oom();
        }
    }
}
@Component
public class FooService {
    List<String> data = new ArrayList<>();
    public void oom() {
        //往同一个ArrayList中不断加入大小为10KB的字符串
        data.add(IntStream.rangeClosed(1, 10_000)
                .mapToObj(__ -> "a")
                .collect(Collectors.joining("")));
    }
}

这边做个小总结

  1. 我们通过MAT可以通过直方图很方便的知道当前堆中哪个对象的数量较多且占据的堆内存较多。同时我们可以通过List objects查看引用链,最终定位到究竟是在哪个类中出现了大量对象导致OOM
  2. 除了直方图外,我们可以使用支配树在更快的时间发现导致OOM的对象
  3. 然后根据线程视图,定位到具体是在哪个地方发生了OOM
  4. 最后呢,我们可以通过OQL查看类,搜索类有几个实例,以及实例在哪几个地方有引用

最后呢,可以到代码地址中下载相关代码,然后本地实践一下。以及本篇文章的内容实际上是学习自极客时间的《Java业务开发常见错误100例》这是一个实战性比较强的专栏,推荐大家也可以去看看文章来源地址https://www.toymoban.com/news/detail-655606.html

到了这里,关于使用MAT分析OOM问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

    1. 前言 熟练掌握 MAT 是 Java 高手的必备能力,但实践时大家往往需面对众多功能,眼花缭乱不知如何下手,小编也没有找到一篇完善的教学素材,所以整理本文帮大家系统掌握 MAT 分析工具。 本文详细讲解 MAT 众多内存分析工具功能,这些功能组合使用异常强大,熟练使用几

    2024年02月09日
    浏览(32)
  • JVM:全面理解线上服务器内存溢出(OOM)问题处理方案(一)

    前段时间生产上遇到了OOM问题,导致服务出现了短时间的不可用,还好处理及时,否则也将酿成大祸。OOM问题也是生产中比较重要的问题,所以本期我们针对OOM问题特别讲解,结合理论与实际案例来带大家彻底攻克OOM问题处理。 要解决问题,我们首先要清楚问题产生的原因。

    2024年02月12日
    浏览(36)
  • 【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍

    本文主要针对于综合层面上进行分析JVM优化方案总结和列举调优参数计划。主要包含: 调优之逃逸分析(栈上分配) 调优之线程局部缓存(TLAB) 调优之G1回收器 -XX:+DoEscapeAnalysis 逃逸分析(Escape Analysis) 逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定

    2024年01月25日
    浏览(47)
  • JVM问题排查

    本文详细说明了Java应用运行过程中几种常见的JVM相关问题,并给出了问题排查步骤。 现象 :Java线程负载过高,JVM内存几乎占满,甚至抛出java.lang.OutOfMemoryError错误。 思路 :通过jmap能查看到对内存中实例,可以查看到哪些类的实例比较多,排查出OOM原因。 工具 :jmap 步骤

    2024年02月09日
    浏览(30)
  • 【JVM】Java内存泄露的排查思路?

    Java内存泄露(Memory Leak)是指在Java程序中,无用的对象占用了 堆内存 ,但无法被垃圾回收器回收释放,从而导致可用内存逐渐减少,最终可能导致内存耗尽或性能下降的问题。 说明一般对于内存泄漏。都是针对 堆 的。 程序一般出现内存泄漏会有 两个状态 一是一启动导致

    2024年02月13日
    浏览(38)
  • 【Jvm】性能调优(上)线上问题排查工具汇总

    产品闭环 产品闭环是能够让 用户主动迭代促进产品发展的方式 。例如一些内容产品,比如 糗事百科 ,种子用户 产出高质量内容 ,举报与赞起到 筛选内容 ,提高内容质量的作用, 内容质量的提升有助于吸引更多用户 。 这就是产品闭环, 产品给予用户需求解决方法,用户

    2024年02月20日
    浏览(33)
  • 【Jvm】性能调优(下)线上问题排查思路汇总

    【Jvm】性能调优(上)线上问题排查工具汇总 【Jvm】性能调优(中)Java中不得不了解的OOM Error 标准参数(-) :所有的JVM实现都必须实现该功能且向后兼容 非标准参数(-X) : 默认Jvm实现该功能 ,但是不保证所有jvm实现都满足,且 不保证向后兼容 非稳定参数(-XX) : 各

    2024年02月21日
    浏览(39)
  • Docker和JVM应用OOM那些事

    Java 应用运行过程中你是否遇到以下类似问题 为什么 Java 应用所在的 Docker 容器内存使用量不会减少? 发生 OOM 后程序还能运行吗? Java 应用所在的容器为什么宕机或者自动重启了? 在回答以上问题前,我们先了解下“OOM”和“JVM 内存管理”。本文涉及的 JVM 相关描述特指

    2024年02月03日
    浏览(34)
  • Java线上故障排查(CPU、磁盘、内存、网络、GC)+JVM性能调优监控工具+JVM常用参数和命令

    根据服务部署和项目架构,从如下几个方面排查: (1)运用服务器:排查内存,cpu,请求数等; (2)文件图片服务器:排查内存,cpu,请求数等; (3)计时器服务器:排查内存,cpu,请求数等; (4)redis服务器:排查内存,cpu,连接数等; (5)db服务器:排查内存,cpu,连接数

    2024年02月07日
    浏览(46)
  • Java JVM分析利器JProfiler 结合IDEA使用详细教程

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 对于我们Java程序员而言,肯定需要对项目工程进行JVM监控分析,最终选择jprofiler,它可以远程链接,使用方便,功能也很强大! JProfiler是一个重量级的JVM监控工具,提供对JVM精确监控,其中堆遍历、

    2024年02月08日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包