⚓【Java 知识晚餐】精心准备的 JVM 分析工具⚓
📚每日箴言📚
如果我们想交朋友,就要先为别人做些事——那些需要花时间、体力、体贴、奉献才能做到的事。
📚前言概述📚
分析 JVM 虚拟机性能与诊断故障,Oracle JDK 自带了问题分析工具,使用命令监控最方便,但是却苦恼那么多命令真心记不住啊!
目前还可以通过可视化工具进行分析,比如:jconsole、jvisualvm/visualvm、MAT 以及在线分析工具等,它们几乎包含全部的信息。 另外 jvisualvm/visualvm 支持远程监控(通过 jmx 和 jmc 的实现机制),但是需要做一些配置。
但是实际生产上还是用 JRE 的居多,并没有那么多花里胡哨的功能,而且即便是 JDK,linux 上也是执行不了那么多 exe 文件的,而且无论从性能或者资源损耗来讲还是命令行最佳合适。作为一个合格的开发者一定要好好了解 JDK 的监控工具哦。
本篇文章不会过多较少所有的指令,否则过于繁琐,主要会介绍最经常用的指令,以后如果真的你的服
务出现问题,可以直接查看本篇文章进行问题解决哦,所以记住收藏,忘记了就来我这里找!!!!
%红色标识着重要的程度哦 %
如果你不想再看下去,那么这里可以给出一些常规出现的操作建议,所谓一招鲜吃遍天
🚀快捷入口🚀
获取垃圾回收器的类型和系统参数(主要查看当前系统内存使用情况) jmap -heap pid
查看应用启动的参数 ((有点类似 jps -v),但是展示的更加详细。) jinfo -flags pid
查看当前各个代区的容量和使用量情况 :jstat -gccapacity pid
FGC、YGC 的总次数和总耗时 :jstat -gc
立即生成 Dump 文件 : jmap -dump:live,format=b,file=dump_001.hprof pid
强制 FullGC : jmap -dump:live
查看线程的运行信息(包括死锁的线程) : jstack -l pid
📚命令工具📚
🔍【JPS(虚拟机进程状况工具)】🔍
JVM Process Status—显示指定系统的所有的虚拟机进程
jps : 显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一 ID;
jps -q :只输出进程的本地虚拟机唯一 ID;
jps -l:输出主类的全名,如果进程执行的是 Jar 包,输出 Jar 路径;
jps -v:输出虚拟机进程启动时 JVM 参数;
jps -m:输出传递给 Java 进程 main() 函数的参数;
🔍【JINFO(虚拟机配置查看工具)】🔍
JVM information—显示虚拟机配置信息,实时地查看和调整虚拟机各项参数
jinfo vmid :输出当前 jvm 进程的全部参数和系统属性 (第一部分是系统的属性,第二部分是 JVM 的参数);
jinfo -flag name vmid :输出对应名称的参数的具体值;
jinfo -flag [+|-]name vmid 开启或者关闭对应名称的参数,使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。
🔪【JSTAT(虚拟机统计查看工具)】🔪
%可以看出我用加粗以及🔪来表示,说明此工具非常重要,其他的不记就算了,这个一定要好好记住 %
JVM statistic —监视虚拟机各种运行状态信息,使用于监视虚拟机各种运行状态信息的命令行工具,
gc: 主要查看 FGC、YGC 的总次数和累计耗时
可以显示本地或者远程(需要远程主机提供 RMI 以及 JMC 的支持)虚拟机进程中的类信息、内存、垃圾收集、JIT 编译等运行数据;
只提供了纯文本控制台环境的服务器上(无 GUI),它将是运行期间定位虚拟机性能问题的首选工具;
jstat -class vmid :显示 ClassLoader 的相关信息;
jstat -compiler vmid :显示 JIT 编译的相关信息;
jstat -gc vmid :显示与 GC 相关的堆信息;
jstat -gccapacity vmid :显示各个代的容量及使用情况;
jstat -gcnew vmid :显示新生代信息;
jstat -gcnewcapcacity vmid :显示新生代大小与使用情况;
jstat -gcold vmid :显示老年代和永久代的信息;
jstat -gcoldcapacity vmid:显示老年代的大小;
jstat -gcpermcapacity vmid :显示永久代大小;
jstat -gcutil vmid :功能和 gc 一样,但是是百分比的形式,读取更友好
加上 -t 参数可以在输出信息上加一个 Timestamp 列,显示程序的运行时间,
例如:jstat -t -gc vmid
🚗实际案例🚗
(1)jstat -gc vmid :显示与 GC 相关的堆信息
查看堆内各个代区的当前容量和当前使用量(当前容量不等于 MaxCapactiy,当前容量是根据条件动态调整的),因为当前容量不等于 Max 容量所以在定位问题的时候,没有太多的使用价值。
(2)jstat -gccapacity vmid
读取各个代区的当前容量、最大容量、当前使用量等信息;
🔪【JMAP(虚拟机内存访问工具)】🔪
JVM Memory(Map) Access Process — 目前我们经常用其生成堆转储快照(查看也可)
jmap -heap pid:查看 JDK 的概况的最好的一个参数
🚗实际案例🚗
(1)JVM 主要参数:垃圾回收器的类型、各种 ratio、当前实际 Size、MaxSize 是多少。
(2)当前各个代区的使用情况:Eden、From、To、Old 区、Perm 区。
参数解读
垃圾回收器: parallel + Concurrent Mark-Sweep
堆区 MaxSize 是 4G,也就是默认是操作系统的 1/4,16G*1/4=4G
堆区低于 40%,或者大于 70% 会自动调整老年代的大小(但是不能低于 xms 的配置 2G,也不能高于 MaxSize 4G)
Perm 区 最大 1G ,如我们配置
老年代(concurrent mark-sweep generation)容量:1715.25MB
年轻代:New Generation + 1 Survivor Space= 299.5MB+33.25MB
堆区的当前容量:1715.25+299.5+33.25=2048M
jmap -dump:live,format=b,file=dump.hprof pid:生成快照文件,然后可以利用工具(比如 jvisualvm)来分析 dump 包,dump 堆到文件,format 指定输出格式,live 指明是活着的对象,file 指定文件名
🚗除此之外🚗
jmap 的作用并不仅仅是为了获取 dump 文件,它还可以查询 finalizer(F-Queue 引用队列)执行队列、Java 堆和永久代的详细信息,如空间使用率、当前使用的是哪种收集器等。和 jinfo 一样,jmap 有不少功能在 Windows 平台下也是受限制的。
jmap 还有一个额外的功能,通过命令触发 FullGC,比如可以执行定时任务,在业务低峰期执行,会自动触发 FullGC,因为在*:live 前会进行 full gc,如果带上 live 则只统计活对象,因此不加 live 的堆大小要大于加 live 堆的大小
不使用 jmap 命令,要想获取 Java 堆转储,使用 “-XX:+HeapDumpOnOutOfMemoryError” 参数,可以让虚拟机在 OOM 异常出现之后自动生成 dump 文件,
Linux 命令下可以通过 kill -3 发送进程退出信号也能拿到 dump 文件。
🔍【JHAT(虚拟机堆内存分析工具)】🔍
JVM Heap Analysis Tools — 目前我们经常用其生成堆转储快照
jhat 主要用于分析 heapdump (切记不是 core dump)文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果。
不过目前,我们一般都会使用类似 GUI 的分析工具进行分析,例如:JvisualVM\VisualVM、或者
MAT、JProfiler、同时还有写在线的 SAS 服务,如:
【fastThread】http://fastthread.io/
【gceasy】https://gceasy.io/、
【heaphero】https://heaphero.io/
还有其他的很多,而具体如何使用我就不说了,谁用谁知道。所以 Jhat 不用也罢
🔪【JSTACK(虚拟机线程快照访问工具)】🔪
JVM Thread Stack — 生成虚拟机当前时刻的线程快照
🚲分析目标🚲
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合;生成线程快照的目的主要是定位线程长时间出现停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的原因。
线程出现停顿的时候通过 jstack 来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者在等待些什么资源。
🚲命令格式🚲
jstack [ option ] pid
jstack [ option ] executable core
将被打印信息的 core dump 文件
jstack [ option ] [server-id@] remote-hostname-or-IP
remote-hostname-or-IP:远程 debug 服务的主机名或 ip, -
server-id:唯一 id,假如一台主机上多个远程 debug 服务。
🚲基本参数🚲
jstack -F pid :当 jstack [-l] pid 没有相应的时候强制打印栈信息。
jstack -l pid :打印关于锁的附加信息,例如属于 java.util.concurrent 的 ownable synchronizers 列表,表示包括线程死锁的信息输出当前应用的线程使用信息,其中包括线程死锁的相关信息
jstack -m pid:打印 java 和 native c/c++框架的所有栈信息.
jstack-h | -help pid :打印帮助信息
🚲实际案例🚲
查找对应 Tomcat 进程号:ps -ef|grep tomcat 导出堆栈信息,查询进程 PID 为 8564
jstack -l 8564 > 8564.stack,下载 8564.stack 并打包为 zip 格式上传到 FastThreadhttps://fastthread.io/,即可。
📚技术彩蛋📚
接下来我们超纲一部分学习内容,首先我们了解一下 JVM 线程堆栈——它是什么?
JVM 线程堆栈是一个给定时间的快照,它能向你提供所有被创建出来的 Java 线程的完整清单,每一个被发现的 Java 线程都会给你如下信息:
线程的名称:经常被中间件厂商用来识别线程的标识,一般还会带上被分配的线程池名称以及状态 (运行,阻塞等等.)
线程类型 & 优先级:例如 : daemon prio=3 中间件程序一般以后台守护的形式创建他们的线程,这意味着这些线程是在后台运行的;它们会向它们的用户提供服务,例如:Java EE 应用程序
Java 线程 ID,例如 : tid=0x000000011e52a800 这是通过 java.lang.Thread.getId()获得的 Java 线程 ID,它常常用自增长的长整形 1..n 实现
原生线程 ID,例如 : nid=0x251c ,原生线程 ID 可以让你获得诸如从操作系统的角度来看那个线程在你的 JVM 中使用了大部分的 CPU 时间等这样的相关信息
Java 线程状态和详细信息,例如: waiting for monitor entry [0xfffffffea5afb000] java.lang.Thread.State: BLOCKED (on object monitor)可以快速的了解到线程状态极其当前阻塞的可能原因
Java 线程栈跟踪::这是目前为止你能从线程堆栈中找到的最重要的数据. 这也是你花费最多分析时间的地方,因为 Java 栈跟踪向提供了你将会在稍后的练习环节了解到的导致诸多类型的问题的根本原因,所需要的 90%的信息。
未完待续 .......
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/196a957eb5a611a66f6d221ed】。文章转载请联系作者。
评论 (2 条评论)