JVM 监控&诊断
Contents
💠
-
- 4.1. Arthas
- 4.2. async-profiler
-
- 6.1. JProfiler
- 6.2. YourKit
- 6.3. Visualvm
- 6.4. MAT
- 6.5. JMC
- 6.6. IBM Heap Analyzer
- 6.7. IntelliJ IDEA
💠 2024-11-18 14:31:55
JVM 监控&诊断
命令行终端
- 标准终端类:jps、jinfo、jstat、jstack、jmap
- 功能整合类:jcmd、vjtools、arthas、greys
可视化界面
- 简易:JConsole、JVisualvm、HA、GCHisto、GCViewer
- 进阶:MAT、JProfiler
命令行推荐 arthas ,可视化界面推荐 JProfiler
此外还有一些在线的平台 gceasy、heaphero、fastthread 。
JVMTI
JVM Tool Interface
JDK自带工具
都是jdk的bin目录下的工具,注意使用时要和目标JVM同一个JDK版本,以及同一个用户。
java
使用方式:
- 执行类:
java [-options] class [args...]
- 执行包:
java [-options] -jar jarfile [args...]
或java -jar [-options] jarfile [args...]
注意 这些Java options都不会生效。
java -jar jarfile [-options] [args...]
java -jar jarfile [args...] [-options]
环境变量的使用
- 传入
java -Dkey=true -jar xxx.jar
- -D 参数 要在 -jar 之前
- 获取
System.getProperty("key", "defaultvalue");
jps
主要用来输出JVM中运行的进程状态信息
- option:
- -q 忽略输出的类名、Jar名以及传递给main方法的参数,只输出pid。
- -m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null。
- -l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。
- -v 输出传给JVM的参数。
- -V 输出通过标记的文件传递给JVM的参数(.hotspotrc文件,或者是通过参数-XX:Flags=指定的文件)
jstat
- option:
- -class 类加载情况
- -compiler 编译统计
- -printcompilation JVM编译方法统计
- 查看内存相关指标
-gcutil
总gc统计情况-gc
gc统计情况-gccapacity
堆内存空间-gcnew
和-gcnewcapacity
新生代gc和内存统计-gcold
和-gcoldcapacity
老年代gc和内存统计-gcpermcapacity
JDK7 永久代-gcmetacapacity
JDK8 元空间
- -t 在第一列输出时间戳
(s)
。该时间戳从jvm启动后开始计时 - -h3 每隔N行输出一次列表头
- $PID 进程号
- interval 输出间隔时间,单位毫秒
- count 输出次数
Demo:
jstat -gcutil -t -h5 7919 1000 50
jinfo
观察运行中的 java 进程的运行环境参数:参数包括 Java System 属性和 JVM 命令行参数
Demo:
- jinfo 14352
- jinfo -sysprops 14352
- 查看JVM参数
jinfo -flags 14352
- jinfo -flag MaxPermSize 14352
jmap
用来查看堆内存使用状况
Demo:
jmap -histo $PID
展示实例和占用内存情况jmap -histo:live $PID
展示存活实例情况 注意会触发FullGC
jmap -heap $PID
展示Java堆的各内存区域大小及占用情况jmap -dump:live,format=b,file=heapLive.hprof $PID
dump下存活对象 注意会触发FullGCjmap -dump:format=b,file=heapLive.hprof $PID
dump所有对象- 失败时 可以尝试 -F 参数,强制dump,但此时的dump文件不一定是完整可打开的。
- 提示attach失败时 可修改
echo 0 > /proc/sys/kernel/yama/ptrace_scope
jmap依赖ptrace实现,此选项放开ptrace仅支持父进程执行的限制
jhat
Java Head Analyse Tool Oracle: jhat
用于分析 jmap 转储出来的堆文件, 分析完后启动一个WebServer, 浏览器打开 127.0.0.1:7000 查看
参数
- -J-mx2g 设置最大内存2g
- -J-d64 64位模式
- -port 端口
使用
- 网页
- 首页 所有类,点击可查看类的实例列表
- 底部 Other Queries 包含: histo,OQL查询,类实例 查看功能
- 比较多个dump
jhat -baseline snapshot_1.hprof snapshot_2.hprof
1,2文件是先后dump产生的- 在底部的类实例
Show instance counts
中能看到多了一列 例如instances (111060 new) of class
- 在底部的类实例
- OQL查询
OQL
|
|
HPROF
HPROF: A Heap/CPU Profiling Tool
heapdumpstamp获取hprof创建时间戳
jstack
jstack [option] pid 主要用来查看某个Java进程内的线程堆栈信息
- Option:
- -F: 强制产生一个线程dump
注意
此方式得到的dump缺失很多信息, 只有线程栈和操作系统线程id,没有线程名,线程cid,锁等信息- 而且相对于没有-F的方式,实现原理完全不一样,见下文链接
- -m: 打印java和native frames
- -l: 打印关于锁的附加信息
- -J-d64: 64位模式
- -F: 强制产生一个线程dump
找出占用CPU最高的线程: 封装的Shell active_cpu_thread
jps 或者 ps aux | grep xxx
得到对应Java进程idtop -Hp 进程id
查看 time 占用最长 或者 CPU占用最高 的线程idprintf %x 线程id
得到 16进制线程idjstack 进程id | grep -A 20 16进制线程id
查看该线程的栈,进而分析到代码
How to Analyze Java Thread Dumps
分析工具和思路
OpenJDK11 jstack output explanation
How to Analyze Java Thread Dumps
扩展:通过短时间内多次获取stack分析出 活锁,死循环,死锁等问题点,但是通常这类问题只能通过修复并重启解决
实现原理
jmap -F and jstack -Fjmap和jstack 默认及加-F选项背后实现机制及优缺点
jcmd
jcmd [pid | main-class] command… | PerfCounter.print | -f filename Oracle jcmd doc
- jcmd 列出所有可操作的JVM进程
- -f filename 执行文件内的命令
command
-
Compiler
- Compiler.codecache
- Compiler.queue
-
GC GC信息,触发GC,堆信息
命令 说明 GC.run 触发一次Full GC GC.heap_info 查看堆使用统计 GC.class_histogram -all 类实例统计 GC.heap_dump -all filename 创建所有对象的dump GC.finalizer_info finalization 队列信息 - 参数
-all
全部对象,如果去除该参数,将触发Full GC来找到所有存活对象
- 参数
-
JFR
- JFR.start 会输出提示信息
- JFR.stop name=1 filename=now.jfr (
name
参数从start执行后的提示信息中获取)
-
JVMTI
-
ManagementAgent
-
System
-
Thread
-
VM
- VM.command_line
- VM.version
- VM.uptime [-date]
- VM.system_properties
-
Memory
- VM.native_memory
jhsdb
JDK9之前通过是Jar方式启动 HSDB CLHSDB。部分功能有被jmap等命令封装 例如 jmap -heap
java -cp .:sa-jdi.jar sun.jvm.hotspot.CLHSDB
HSDB需要和目标JVM同一个版本- help 查看帮助
- jseval 执行javascript
- attach:连接到目标进程戒core
- universe:查看Java heap的情况
- inspect:查看某个地址对应的数据结构的内容
- scanoops:扫描某个地址段的Java对象
jstack jmap jinfo jsnap 等命令功能的迁移和加强
例如
jmap -heap pid
=>jhsdb jmap --heap --pid pid
终端类工具
Arthas
Github: Arthas
阿里巴巴
async-profiler
async-profiler
CPU和内存采样 渲染火焰图
jvm-sandbox
图形化工具
Heap Dump Analysers
Java Monitoring ToolsProfile APM log 等多个解决思路
JProfiler
YourKit
Visualvm
参考: java内存泄漏的定位与分析 使用 VisualVM 进行性能分析及调优
参考: JVisualVM简介与内存泄漏实战分析
Local
Remote
- 通常使用两种方式连接远程JVM: JMX jstatd
jmx
jstatd
- vim jstatd.all.policy
1 2 3 4
grant codebase "file:${java.home}/../lib/tools.jar" { permission java.security.AllPermission; };
- jstatd -J-Djava.security.policy=jstatd.all.policy -p 12028 -J-Djava.rmi.server.logCalls=true
- open jvisualvm create a remote with jstatd by above port 12028
- vim jstatd.all.policy
提高效率的使用场景
- 可以使用 Profiler 下的JDBC,操作业务流程,获取所有执行的SQL,用来做索引优化,或排查问题
- 注意可能不准确,需要对监控到的SQL有质疑的想法
- 真实案例: 监控到对MySQL执行的某条SQL为
xxx in ('NULL', 2, 4)
. 应用写法不规范未过滤集合中的null值就拼接进了条件 - 实际上MySQL驱动执行的SQL是
xxx in (NULL, 2, 4)
这会导致此子句永远是false,详见 MySQL 条件操作符 - Clone Visualvm的代码后 通过GUI找功能实现,发现可疑方法 org.graalvm.visualvm.lib.jfluid.results.jdbc.SQLStatement#getFullSql
- 通过arthas watch该方法的返回后,确认是这个方法的问题,
- 结论为:基于 PreparedStatement 得到执行SQL的实现方式和MySQL驱动的不一样。
- 真实案例: 监控到对MySQL执行的某条SQL为
- 注意可能不准确,需要对监控到的SQL有质疑的想法
MAT
Memory Analyzer tool(MAT) | Official Site | download
参考: JAVA Shallow heap & Retained heap
参考: 利用MAT分析JVM内存问题,从入门到精通
Official Doc: OQL Syntax
注意: 有这样的一种场景, 从数据库获取大量的数据创建为对象, 导致瞬间的OOM 这时候即使使用 jmap 去 dump 了快照, 也看不到占用大量内存的对象, 因为MAT默认展示的是GC可达对象,需要在菜单选择看不可达对象
分析思路:
- 对象: histogram, Top ,
- 线程:
- 类加载器: histogram -> basic -> merge classloader
- 不可达对象:
利用安装目录下的 ParseHeapDump.sh 命令行解析 dump的 hprof文件 全部解析: ParseHeapDump.sh ~/Downloads/java_pidxxx.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
- ParseHeapDump.sh ~/Downloads/java_pidxxx.hprof org.eclipse.mat.api:suspects
- ParseHeapDump.sh ~/Downloads/java_pidxxx.hprof org.eclipse.mat.api:overview
- ParseHeapDump.sh ~/Downloads/java_pidxxx.hprof org.eclipse.mat.api:top_components
并且可以发现结果文件为html,可以挂载到nginx等web服务器共享结果
比较多个dump文件
JMC
- 通过JMX连接目标JVM 实时监控应用指标
- 通过对运行中的JVM进行飞行记录
Flight Recorder
, 分析指定时间内代码的可优化点,指标值变化情况
指标值包括:JVM的 内存,CPU,GC,线程,类加载,网络和文件IO; 宿主机的CPU、内存等指标,联合做参考
目标JVM开启远程访问JMX
注意JDK6后就默认开启了进程访问JMX
JMC 9自身需要JDK17以上运行,可以监控JDK 7u40及往后的版本
实践场景
- JFR分析某个业务场景的性能问题
- 启动应用,启动JMC,JMC连接到业务JVM后,开启一段时间的JFR,然后直接操作业务逻辑,JFR结束后可以看到
IBM Heap Analyzer
IntelliJ IDEA
Author Kuangcp
LastMod 2018-11-21