性能文章>java内存溢出问题分析过程>

java内存溢出问题分析过程原创

1年前
7089214

前言

java程序的性能问题定位,一直都是开发者需要面对的一个“拦路虎”, 在前面的两篇文章中,已经介绍了Heap dump的概念和生成方式,以及Shallow heap和Retained heap以及GC ROOT的概念,本篇文章,我们继续来介绍一些新的概念和基于一个dump案例,详尽的介绍,在程序OOM后,改如何去定位具体原因。

再次提及dominator tree(支配树)

如果你玩过竞技类游戏,肯定会很熟悉Dominating -主宰比赛这个单词。

image.png

在Memory Analyzer工具中提供了对象图的支配树。将对象引用图转换为dominator tree可以让轻松地确定Retained heap最大内存块和对象之间保持活动的依赖关系,相当于主宰了整个JVM的感觉。

我们把java对象之间的引用关系看做一张有向图,如果所有指向Y的对象路径都要经过X,则我们说X支配Y。如果X是离对象Y最近的支配对象,则我们说对象X是Y的直接支配者( immediate dominator)。

再强化记忆一下,X对象要直接支配Y,必须满足这两点:

  • 指向Y的对象路径都要经过X。

  • X对象是离Y最近的支配对象。

image.png

左边是对象的引用图,右边是支配树。

C节点的子树就是所有被C支配的节点的集合,也称为C的Retained Set。

由图可以看出,C是E的直接支配节点,所以C的上级支配节点B也可以支配E。

dump分析初步

首先用MemoryAnalyzer工具打开dump文件。

image.png

从整体情况可以看出,1.6 gb的堆内存,有大对象占了1.1g。

怀疑是有内存泄漏,我们通过Leak Suspect Report报告查看

image.png

内存泄漏分析报告显示有两项问题:

  • 一是WebappClassLoader 类加载器装载的A.A[][] 对象占了约1.2g(70.40%)。

  • 二是一个名为TP-Processor9的线程持有本地变量多达337M(占了19.58%)。

通过分析报告,我们初步可以推断出OOM的问题应该出在这两个地方,我们逐个击破。

内存泄漏点一

先来看类装载器加载的AA对象。我们点开内存泄漏报告的Detail,查看其详情。

Shortest Paths To the Accumulation Point视图可以看出正是和org.apache.catalina.loader.WebappClassLoader这个GC root相连导致当前Retained Heap占用相当大的对象无法被回收,而对象数量居然达到了170288个。

image.png

Accumulated Objects in Dominator Tree视图,可以看出AA对象中,到底是什么内嵌对象占用heap高。

image.png

可以看出,170288个AA对象数组内部,主要是AH对象 和 AM对象。

我们继续向下看,通过按class类分组,来看看具体占用比例情况。

image.png

按class分组后,冒出了一个Af对象,反倒AH占用不是那么多了。

小结:AH/AM/Af三个对象占用堆内存很高,并且它们的gc root是WebappClassLoader。

内存泄漏点二

image.png

TP-Processor9 线程本身就是GC root,故只有一条数据。

以这个线程为GC ROOT来看看,它的支配树是什么样的?

image.png

可以看到19.58%的Retained Heap就是来源于TP-Processor9 线程本身。这意味着,如果这个线程能被gc回收掉,则至少能释放19.58%的堆内存。

image.png

以TP-Processor9 线程为gc root的支配树,按class分类,可以发现Am对象本身占用163m左右。

image.png

Detail明细的最后由于当前怀疑泄露点为TP-Processor9 线程对象,故展示了线程明细信息,调用栈信息。

小结:TP-Processor9 线程内部可能导致内存泄漏。

整合两个泄漏点结论

从两个泄漏点,得出的结论,我们可以将问题定位到如下元素上:TP-Processor9 线程、170288个AA对象数组、AM、AH对象。

我们来看看AA对象数组的(Outgoing Reference)引用其他外部对象的情况

image.png

可以看到com.fr.report.core.A.A[170288][] @ 0xcfdb62a0 这个对象引用外部对象的情况,一共是170289个 com.fr.report.core.A.A[25] 对象。

并且其Shallow Heap 和Retained Heap大小一样。170289 * 120 = 20434680。约占20M内存。

所以这个对象应用的外部对象,不是根因。

接下来,再分析Incomming Reference(被其他外部对象引用的情况)。

image.png

可以看到com.fr.report.core.A.A[170288][] @ 0xcfdb62a0

这个包含170288个元素的对象,主要被 com.fr.report.worksheet.PageRWorkSheet @ 0xcfd02188 对象持有。

出现了一系列的ReportPage和ClippedECPage对象。

image.png

从依赖树和对象地址可以知道,ClippedECPage引用ReportPage对象。

所以只需要重点关注ClippedECPage对象。继续分析ClippedECPage对象的依赖树如下:

其他的 Shallow Heap占用都不高,唯独一个对象数组,占用较大,并且它的Retained Heap很大。

问题应该就出在ClippedECPage类上,进一步分析它存储的 com.fr.page.ReportPage。这个对象是:用于展示及打印的页面 执行完一个多Sheet的Report后, 会生成多个ReportPage。分析它的属性:

image.png

连续查看了两个对象,发现其中的属性,currentPageNumber为591和592。

image.png

总页数为599. 可以推断出,是在做分页操作。

image.png

可以看到当时浏览器的信息

image.png

操作的文件:xxx/customized/xxx表.xxx

结论

结合ReportPage类的作用:用于展示及打印的页面 执行完一个多Sheet的Report后, 会生成多个ReportPage。

最后结论为:

在执行查询时间段为:2018/6/8 15:57:15 - 2018/6/8 16:0:53 一次性打印599页数据,导致OOM,程序宕机崩溃。

至此,就完成了一个Dump文件的分析,为了更好的学习mat相关知识,我准备了一个mat的操作手册,比较全面。

image.png

请先登录,再评论

操作手册在哪下载?

1年前
回复 H同学:

添加我们哒微信发您(perfma)

1年前回复

够详细的,就需要这种照顾我们菜鸟的😁

1年前

为你推荐

字符串字面量长度是有限制的
前言 偶然在一次单元测试中写了一个非常长的字符串字面量。 正文 在一次单元测试中,我写了一个很长的字符串字面量,大概10万个字符左右,编译时,编译器给出了异常告警 `java: constant
多次字符串相加一定要用StringBuilder而不用-吗?
今天在写一个读取Java class File并进行分析的Demo时,偶然发现了下面这个场景(基于oracle jdk 1.8.0_144): ``` package test; public c
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得
高吞吐、低延迟 Java 应用的 GC 优化实践
本篇原文作者是 LinkedIn 的 Swapnil Ghike,这篇文章讲述了 LinkedIn 的 Feed 产品的 GC 优化过程,虽然文章写作于 April 8, 2014,但其中的很多内容和
「每日五分钟,玩转 JVM」:久识你名,初居我心
聊聊 JVMJVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别。JVM可以说和我们是老朋友了
据说99.99%的人都会答错的类加载的问题
概述首先还是把问题抛给大家,这个问题也是我厂同学在做一个性能分析产品的时候碰到的一个问题。 同一个类加载器对象是否可以加载同一个类文件多次并且得到多个Class对象而都可以被java层使用吗请仔细注意
Java多线程——并发测试
编写并发程序时候,可以采取和串行程序相同的编程方式。唯一的难点在于,并发程序存在不确定性,这种不确定性会令程序出错的地方远比串行程序多,出现的方式也没有固定规则。那么如何在测试中,尽可能的暴露出这些问
Java多线程知识小抄集(一)
本文主要整理笔者遇到的Java多线程的相关知识点,适合速记,故命名为“小抄集”。本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆。 1.interr