# 前言 后文会从 Windows、Linux 两个系统来做示例展示,有人会有疑问了:为什么要说 Windows 版的 ? 目前市面上还是有很多 Windows 服务器的,应用于传统行业、政府结构、医疗行业 等等;两个系统下的情况都演示下,有备无患,后文中用到了两个工具:Processor Explorer、MAT,它们是什么,有什么用,怎么用,本文不做介绍,以下内容有部分参考[JVM调优学习笔记](https://mp.weixin.qq.com/s/tmb31nJQafKB8ydbMvZ1Hg),感兴趣的小伙伴也可以看看! # cpu 100% 下面的示例中, cpu 的占有率没到 100%,只是比较高,但是排查方式是一样的,希望大家不要钻牛角尖 Windows **1、找到 cpu 占有率最高的 java 进程号** ![](https://p6-tt.byteimg.com/origin/pgc-image/beaffd0433cf47eb9bc18dc551a161a8?from=pc) PID: 20260 **2、根据进程号找到 cpu 占有率最高的线程号** 双击刚刚找到的 java 进程 ![](https://p6-tt.byteimg.com/origin/pgc-image/73e1e09a66684995a1c59965fd9efe88?from=pc) 线程号: 15900 ,转成十六进制: 3e1c **3、利用** **jstack** **生成虚拟机中所有线程的快照** 命令: jstack -l {pid} > {path} ![](https://p3-tt.byteimg.com/origin/pgc-image/fdbf5af95edc436a92d678f010691020?from=pc) 文件路径: D:\20260.stack **4、线程快照分析** 我们先浏览下快照内容 ![](https://p1-tt.byteimg.com/origin/pgc-image/7e2412e5958049ddaf1ed8909e0915da?from=pc) 内容还算比较简洁,线程快照格式都是统一的,我们以一个线程快照简单说明下 "main" #1 prio=5 os\_prio=0 tid=0x0000000002792800 nid=0x3e1c runnable 0x00000000025cf000 ![](https://p6-tt.byteimg.com/origin/pgc-image/6af252c8bd334200b945a9fae5e92e7a?from=pc) 我们前面找到占 cpu 最高的线程号: 15900 ,十六进制: 3e1c ,用 3e1c 去快照文件里面搜一下 ![](https://p6-tt.byteimg.com/origin/pgc-image/ab21ccccdfa8408a885b4857a4381f2d?from=pc) 自此,找到问题 ![](https://p1-tt.byteimg.com/origin/pgc-image/33fe9a75a69b4a3eb10c52bfe6c3c073?from=pc) Linux 排查方式与 Windows 版一样,只是命令有些区别 1、找到 cpu 占有率最高的 java 进程号 使用命令: top -c 显示运行中的进程列表信息, shift + p 使列表按 cpu 使用率排序显示 ![](https://p1-tt.byteimg.com/origin/pgc-image/c28f8b949a4044af81af2799ec17b32d?from=pc) PID = 2227 的进程,cpu 使用率最高 **2、根据进程号找到 cpu 占有率最高的线程号** 使用命令: top -Hp {pid} ,同样 shift + p 可按 cpu 使用率对线程列表进行排序 ![](https://p6-tt.byteimg.com/origin/pgc-image/b91a2fbc2db3472bb880466996facd2b?from=pc) PID = 2228 的线程消耗 cpu 最高,十进制的 2228 转成十六进制 8b4 **3、利用** **jstack** **生成虚拟机中所有线程的快照** ![](https://p6-tt.byteimg.com/origin/pgc-image/bf5f75e4423f472ba2062f26dad87287?from=pc) **4、线程快照分析** 分析方式与 Windows 版一致,我们可以把 2227.stack 下载到本地进行分析,也可直接在 Linux 上分析 在 Linux 上分析,命令: cat 2227.stack |grep '8b4' -C 5 ![](https://p3-tt.byteimg.com/origin/pgc-image/d8328213cc874c1fbf8dc72956018ea8?from=pc) 至此定位到问题 ![](https://p6-tt.byteimg.com/origin/pgc-image/c0fc631f42524ac59710d1d100e987ad?from=pc) 不管是在 Windows 下,还是在 Linux 下,排查套路都是一样的 ![](https://p1-tt.byteimg.com/origin/pgc-image/54965cac64f241c9a33b2250c7b0538b?from=pc) # 内存泄露 同样的,Windows、Linux 各展示一个示例 Windows 1、找到内存占有率最高的进程号 PID ![](https://p3-tt.byteimg.com/origin/pgc-image/f0dbcbd4498846499cf343c9f3181467?from=pc) 第一眼看上去, idea 内存占有率最高,因为我是以 idea 启动的 java 进程;idea 进程我们无需关注,我们找到内存占有率最高的 java 的 PID: 10824 **2、利用** **jmap** **生成堆转储快照** 命令: jmap -dump:format=b,file={path} {pid} ![](https://p1-tt.byteimg.com/origin/pgc-image/9183f537a2d94a7bbc64e8678febb0c3?from=pc) dump 文件路径: D:\heapdump\_108244.hprof **3、利用** **MAT** **分析 dump 文件** MAT:Memory Analyzer Tool,是针对 java 的内存分析工具;下载地址: ![](https://p1-tt.byteimg.com/origin/pgc-image/f3a4a55d0037446fac5c82a3e54e4658?from=pc) 选择对应的版本,下载后直接解压;默认情况下,mat 最大内存是 1024m ,而我们的 dump 文件往往大于 1024m,所以我们需要调整,在 mat 的 home 目录下找到 MemoryAnalyzer.ini ,将 -Xmx1024m 修改成大于 dump 大小的空间, 我把它改成了 -Xmx4096m 接着我们就可以将 dump 文件导入 mat 中,开始 dump 文件的解析 ![](https://p6-tt.byteimg.com/origin/pgc-image/edaad1beb109491da8d649378f7c1910?from=pc) 解析是个比较漫长的过程,我们需要耐心等待 ![](https://p6-tt.byteimg.com/origin/pgc-image/629ef8f9534843b4abc22ae49ac9c5aa?from=pc) 解析完成后,我们可以看到如下概况界面 ![](https://p6-tt.byteimg.com/origin/pgc-image/4109dd8b09144d17b991abb0df4d8e77?from=pc) 各个窗口的各个细节就不做详细介绍了,有兴趣的可自行去查阅资料;我们来看看几个图:饼状图、直方图、支配树、可疑的内存泄露报告 **饼状图** ![](https://p3-tt.byteimg.com/origin/pgc-image/513a6262fb2b430db3b8f4c25b5fb5f6?from=pc) 可以看出, com.lee.schedule.Schedule 对象持有 1G 内存,肯定有问题 **直方图** ![](https://p1-tt.byteimg.com/origin/pgc-image/3bfa3e6366634c439e7bc0e5fb30f984?from=pc) 我们看下 Person 定义 ![](https://p6-tt.byteimg.com/origin/pgc-image/1c1f830cc20d459ea65b4c0993c2760d?from=pc) 可想而知,上图标记的几项都与 Person 有关 支配树 ![](https://p6-tt.byteimg.com/origin/pgc-image/6f9ce934612a4e62a3614f3e7e498f87?from=pc) 这就非常直观了,Schedule 中的 ArrayList 占了 99.04% 的大小 可疑的内存泄露报告 ![](https://p6-tt.byteimg.com/origin/pgc-image/d493b118e6ce43b7ac4a971fd28ad917?from=pc) 通过这些数据,相信大家也能找到问题所在了 ![](https://p3-tt.byteimg.com/origin/pgc-image/fb046ef89055473b9c4065fc7a7e7870?from=pc) Linux 排查方式与 Windows 一样,只是有稍许的命令区别 1、找到内存占有率最高的进程号 使用命令: top -c 显示运行中的进程列表信息, shift + m 按内存使用率进行排序 ![](https://p1-tt.byteimg.com/origin/pgc-image/32c229773b894071810afc77cb6ca480?from=pc) 进程号: 2527 2、利用 jmap 生成堆转储快照 命令: jmap -dump:format=b,file={path} {pid} ![](https://p6-tt.byteimg.com/origin/pgc-image/860c98560147488591ac0a47a2f226f6?from=pc) 堆转储快照文件路径: /opt/heapdump\_2527.hprof 3、利用 MAT 分析堆转储快照 将 heapdump\_2448.phrof 下载到本地,利用 MAT 进行分析;分析过程与 Windows 版完全一致 ![](https://p6-tt.byteimg.com/origin/pgc-image/ab35d4c026214ae390cb8049623f9289?from=pc) 自此,定位到问题 Windows下 与 Linux 下,排查流程是一样的 ![](https://p6-tt.byteimg.com/origin/pgc-image/b2459e1d7af741219ff76a23bc9b237d?from=pc) # 总结 # JVM 常用命令 jps:列出正在运行的虚拟机进程 jstat:监视虚拟机各种运行状态信息,可以显示虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据 jinfo:实时查看和调整虚拟机各项参数 jmap:生成堆转储快照,也可以查询 finalize 执行队列、Java 堆和永久代的详细信息 jstack:生成虚拟机当前时刻的线程快照 jhat:虚拟机堆转储快照分析工具 与 jmap 搭配使用,分析 jmap 生成的堆转储快照,与 MAT 的作用类似 # 排查步骤 1、先找到对应的进程: PID 2、生成线程快照 stack (或堆转储快照: hprof ) 3、分析快照(或堆转储快照),定位问题 # 内存泄露、内存溢出和 CPU 100% 关系 ![](https://p3-tt.byteimg.com/origin/pgc-image/399092446cce4d06a6f59a2c2a0483b8?from=pc) # 常用 JVM 性能检测工具 Eclipse Memory Analyer、JProfile、JProbe Profiler、JVisualVM、JConsole、Plumbr,怎么样!玩转的JVM内存模型的方法学会了嘛?小编这里准备了一些[Java后端的面试真题](https://mp.weixin.qq.com/s/VZ7wormwowlSPnA_XAnZaw),你也可以来挑战一下!