关于jvm:java获取到heapdump文件后如何快速分析

43次阅读

共计 1622 个字符,预计需要花费 5 分钟才能阅读完成。

原创:扣钉日记(微信公众号 ID:codelogs),欢送分享,非公众号转载保留此申明。

简介

在之前的 OOM 问题复盘之后,本周,又一 Java 服务呈现了内存问题,这次问题不重大,只会触发堆内存占用高报警,没有触发 OOM,但好在之前的复盘中总结了 dump 脚本,会在堆占用高时主动执行 jstack 与 jmap,使得咱们胜利保留了问题现场。

查看堆占用散布

发现有 heapdump 文件后,我立马拷贝到本机,并应用 MAT 剖析,如下:

很显然,如同是什么接口调配了十分大的 String 对象,一个 String 对象约 200MB,那它是哪调配的呢?

查找大对象调配线程

这个调配行为必定是某个线程做的,而线程是最常见的 GC Root,因而只有查找对象的 GC Root 即可,如下:

找到了大对象对应的调配线程是 http-nio-8088-exec-6,如下:

查看线程栈

如何查看这个线程在干什么呢?在 MAT 中摸索了一会,没找到相干内容,回想起咱们的 dump 脚本中记录了 jstack,关上看看,如下:

能够发现,这个线程正在做 json 序列化,但我认真找了好一会,也没有找到相干接口的 Controller,这是因为线程曾经执行完了 Controller 外面的逻辑,之后返回接口响应数据时调配的大对象。

可是,线程栈中没有业务代码,就没法定位是哪个接口有问题了。。。

查看 accesslog 日志

思考到调配大对象的接口必定会很慢,于是我转向查看 tomcat 的 accesslog 日志,如下:

终于,找到了问题接口,这个接口是用来查问商品数据的,当输出 3 时会查问出所有 3 结尾的商品,而这有 20w+ 数据,解决问题很简略,加个 limit 完事。

排查过程复盘

然而,我始终有个习惯,就是解决一个问题后,我会反思一下问题解决过程中有多少运气成分。

如果你常常浏览排查问题类的技术文章,就会发现不少文章,两头忽然有一步定位到了问题根因,可能是忽然发现了一个线索,或是硬看代码看进去的,或是猜想某处有问题,我感觉这种排查过程都有不少运气成分,我心愿问题是通过多年实践根底的积攒和对诊断工具的纯熟应用,而有章法的一步步查出来的。

而下面通过 accesslog 可能定位到问题,有肯定的运气成分,因为本次内存问题不极其,如果此接口申请量大,那就会霎时触发屡次 FGC,进而会影响其它接口也变慢,进而无奈分辨出哪个是导致问题的接口!

我想,从实践上来说,Java 堆文件外面,应该有线程栈以及线程栈上的参数,因为线程是对象,参数也是对象,它们理当都在堆里,于是我找了个闲暇工夫,又摸索起 MAT 这个工具了。

MAT 查看线程栈

摸索了一会,我就发现有这样一个按钮,能够查看线程信息,如下:

找到后面说的线程 http-nio-8088-exec-6,开展后,就能够发现线程栈以及栈上的参数,如下:

这就找到了申请的 Request 参数对象,再将 Request 对象屡次开展后,就能够找到接口 url 信息,如下:

嗯,这样剖析 heapdump 文件真 tm 的高效啊😁

MAT 下载地址:https://www.eclipse.org/mat/downloads.php

VisualVM 查看线程栈

思考到不少同学习惯用 VisualVM 剖析 heapdump,这里也放一下 VisualVM 的应用办法。

首先,加载 heapdump 文件,如下:

而后抉择相应对象,右键抉择 Select in Threads,如下:

定位到线程栈后,找到要查看的 Request 对象,点击进入,如下:

同样,开展 Request 对象后,可找到 url 信息,如下:

VisualVM 下载地址:https://visualvm.github.io/download.html

总结

尽管我也用 MAT 很屡次了,但每次问题都太简略,以至于没有深刻应用过 MAT,导致到当初才晓得有如此便捷的剖析门路。

如果你对咱们的主动 dump 脚本感兴趣,可看看我之前写的这两篇文章。
一次线上 OOM 问题的集体复盘
jmap 执行失败了,怎么获取 heapdump?

正文完
 0