简介
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并且能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。官方文档
用途
Arthas 对于解决线上问题有很大帮助,无需 JVM 重启,无需代码更改。Arthas 作为观察者永远不会暂停正在运行的线程。当出现偶发性事件时非常有用。
- 反编译 class 文件,确认自己的改动是否提交
- 查看指定类文件是从哪个jar包加载的, 为什么会发生相关异常
- 方法执行耗时及数据监控
- 快速定位应用的热点,生成火焰图
- 监控到 JVM 的实时运行状态
- 生成堆栈信息文件
- 查看指定线程信息,查看指定线程的堆栈
- 强制GC
下载及安装
windows环境
从 Maven仓库下载 Arthas 资源,压缩资源如下所示。
将下载下来的压缩包解压,其中 math-game.jar 是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果;arthas-boot.jar 是 Arthas 的核心程序,执行该程序的用户需要和目标进程具有相同的权限 ,可以在命令行通过 java -jar arthas-boot.jar
命令启动Arthas。
Linux 环境
通过curl命令在线下载资源,然后启动
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
使用
Arthas 依赖JDK 提供的一些工具,如 jps, jstack等,所以要配置Java环境变量保证命令行中可以找到这些命令。
启动Arthas
java -jar arthas-boot.jar
Arthas 会使用 jps 扫描出 Java 进程以列表形式展示, 使用者输入名称对应的序号选择指定进程。
常用命令
jvm
查看当前 JVM 信息, 可以通过该命令查看死锁线程数(DEADLOCK-COUNT),当前活跃线程数(COUNT)等。
RUNTIME
----------------------------------------------------------------------------------------------------
MACHINE-NAME 202416@iZwz92hm2mifjerthhuqdyZ
JVM-START-TIME 2024-07-16 16:23:22
MANAGEMENT-SPEC-VERSION 1.2
SPEC-NAME Java Virtual Machine Specification
SPEC-VENDOR Oracle Corporation
SPEC-VERSION 1.8
VM-NAME OpenJDK 64-Bit Server VM
VM-VENDOR Red Hat, Inc.
VM-VERSION 25.312-b07
INPUT-ARGUMENTS []
CLASS-PATH math-game.jar
BOOT-CLASS-PATH /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre/lib/
resources.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x
86_64/jre/lib/rt.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.
el8_5.x86_64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-1.8.0-openjdk-1
.8.0.312.b07-2.el8_5.x86_64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-
openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre/lib/jce.jar:/usr/lib/jvm/jav
a-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre/lib/charsets.jar:/us
r/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre/lib/jfr
.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre
/classes
LIBRARY-PATH /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
----------------------------------------------------------------------------------------------------
CLASS-LOADING
----------------------------------------------------------------------------------------------------
LOADED-CLASS-COUNT 3863
TOTAL-LOADED-CLASS-COUNT 3863
UNLOADED-CLASS-COUNT 0
IS-VERBOSE false
----------------------------------------------------------------------------------------------------
COMPILATION
----------------------------------------------------------------------------------------------------
NAME HotSpot 64-Bit Tiered Compilers
TOTAL-COMPILE-TIME 1204
[time (ms)]
----------------------------------------------------------------------------------------------------
GARBAGE-COLLECTORS
----------------------------------------------------------------------------------------------------
PS Scavenge name : PS Scavenge
[count/time (ms)] collectionCount : 6
collectionTime : 35
PS MarkSweep name : PS MarkSweep
[count/time (ms)] collectionCount : 1
collectionTime : 44
----------------------------------------------------------------------------------------------------
MEMORY-MANAGERS
----------------------------------------------------------------------------------------------------
CodeCacheManager Code Cache
Metaspace Manager Metaspace
Compressed Class Space
PS Scavenge PS Eden Space
PS Survivor Space
PS MarkSweep PS Eden Space
PS Survivor Space
PS Old Gen
----------------------------------------------------------------------------------------------------
MEMORY
----------------------------------------------------------------------------------------------------
HEAP-MEMORY-USAGE init : 31457280(30.0 MiB)
[memory in bytes] used : 30298096(28.9 MiB)
committed : 67633152(64.5 MiB)
max : 427294720(407.5 MiB)
NO-HEAP-MEMORY-USAGE init : 2555904(2.4 MiB)
[memory in bytes] used : 30311920(28.9 MiB)
committed : 31260672(29.8 MiB)
max : -1(-1 B)
PENDING-FINALIZE-COUNT 0
----------------------------------------------------------------------------------------------------
OPERATING-SYSTEM
----------------------------------------------------------------------------------------------------
OS Linux
ARCH amd64
PROCESSORS-COUNT 2
LOAD-AVERAGE 0.06
VERSION 4.18.0-193.14.2.el8_2.x86_64
----------------------------------------------------------------------------------------------------
THREAD
----------------------------------------------------------------------------------------------------
COUNT 14
DAEMON-COUNT 13
PEAK-COUNT 14
STARTED-COUNT 17
DEADLOCK-COUNT 0
----------------------------------------------------------------------------------------------------
FILE-DESCRIPTOR
----------------------------------------------------------------------------------------------------
MAX-FILE-DESCRIPTOR-COUNT 65535
OPEN-FILE-DESCRIPTOR-COUNT 67
dashboard
显示当前系统的实时数据面板。当运行在 Ali-tomcat 时,会显示当前 tomcat 的实时信息,如 HTTP 请求的 qps, rt, 错误数, 线程池信息等等。
USAGE:
dashboard [-h] [-i <value>] [-n <value>]
SUMMARY:
Overview of target jvm's thread, memory, gc, vm, tomcat info.
OPTIONS:
-h, --help this help
-i, --interval <value> The interval (in ms) between two executions, default is 5000 ms.
-n, --number-of-execution <value> The number of times this command will be executed.
示例:
-
dashboard -i 7000
:每7秒刷新一次实时数据, 默认为5秒 -
dashboard -n 2
:该命令被执行的次数,如此表示该命令一共执行2次 -
dashboard -i 7000 -n 2
:每7秒刷新一次实时数据,一共刷新2次 -
dashboard
:每5秒刷新一次实时数据
heapdump
dump Java 堆栈信息,类似 jmap 命令的 heap dump 功能
USAGE:
heapdump [-h] [-l] [file]
SUMMARY:
Heap dump
OPTIONS:
-h, --help this help
-l, --live Dump only live objects; if not specified, all objects in the heap
are dumped.
<file> Output file
示例:
-
heapdump
: dump 到临时文件,一般在 /tmp 目录下,文件名按特定规则生成。 -
heapdump -l
:只 dump live 对象。 -
heapdump ./heapdump.hprof
: dump 到指定文件。 -
heapdump -l ./heapdump.hprof
: dump live 对象到指定文件。
thread
查看当前线程信息,查看线程的堆栈,使用这个命令会产生一定开销,可以通过拉长采样间隔时间来降低其带来的影响。
USAGE:
thread [--all] [-h] [-b] [--lockedMonitors] [--lockedSynchronizers] [-i <value>] [--state <value
>] [-n <value>] [id]
SUMMARY:
Display thread info, thread stack
OPTIONS:
--all Display all thread results instead of the first page
-h, --help this help
-b, --include-blocking-thread Find the thread who is holding a lock that blocks the most number
of threads.
--lockedMonitors Find the thread info with lockedMonitors flag, default value is f
alse.
--lockedSynchronizers Find the thread info with lockedSynchronizers flag, default value
is false.
-i, --sample-interval <value> Specify the sampling interval (in ms) when calculating cpu usage.
--state <value> Display the thead filter by the state. NEW, RUNNABLE, TIMED_WAITI
NG, WAITING, BLOCKED, TERMINATED is optional.
-n, --top-n-threads <value> The number of thread(s) to show, ordered by cpu utilization, -1 t
o show all.
<id> Show thread stack
示例:
-
thread
:显示所有匹配的线程。 -
thread 1
:显示指定线程的运行堆栈,其中 1 代表的是由thread
命令查询出来的 ID 。 -
thread -n -1
:-1 表示展示所有线程并打印堆栈。 -
thread -n 5
:展示当前最忙的前 5 个线程并打印堆栈。 -
thread -b
:找出当前阻塞其他线程的线程,v3.7.2 版本暂时只支持找出 synchronized 关键字阻塞住的线程,不支持 java.util.concurrent.Lock。 -
thread -i 2000
:指定采样时间间隔,单位毫秒 。 -
thread --state BLOCKED
:查看指定状态的线程,状态可为NEW、RUNNABLE、TIMED_WAITI NG、WAITING、BLOCKED、TERMINATED。
trace
trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路,可以用于统计接口耗时,定位和发现因为RT高导致的性能问题。
USAGE:
trace [--exclude-class-pattern <value>] [-h] [-n <value>] [--listenerId <value>] [-m <value>] [-
p <value>] [-E] [--skipJDKMethod <value>] [-v] class-pattern method-pattern [condition-express]
SUMMARY:
Trace the execution time of specified method invocation.
The express may be one of the following expression (evaluated dynamically):
target : the object
clazz : the object's class
method : the constructor or method
params : the parameters array of method
params[0..n] : the element of parameters array
returnObj : the returned object of method
throwExp : the throw exception of method
isReturn : the method ended by return
isThrow : the method ended by throwing exception
#cost : the execution time in ms of method invocation
OPTIONS:
--exclude-class-pattern <va exclude class name pattern, use either '.' or '/' as separator
lue>
-h, --help this help
-n, --limits <value> Threshold of execution times
--listenerId <value> The special listenerId
-m, --maxMatch <value> The maximum of matched class.
-p, --path <value> path tracing pattern
-E, --regex Enable regular expression to match (wildcard matching by default)
--skipJDKMethod <value> skip jdk method trace, default value true.
-v, --verbose Enables print verbose information, default value false.
<class-pattern> Class name pattern, use either '.' or '/' as separator
<method-pattern> Method name pattern
<condition-express> Conditional expression in ognl style, for example:
TRUE : 1==1
TRUE : true
FALSE : false
TRUE : 'params.length>=0'
FALSE : 1==2
'#cost>100'
示例:
-
trace org.apache.commons.lang.StringUtils isBlank
:跟踪 org.apache.commons.lang.StringUtils 类中的 isBlank 方法。 -
trace *StringUtils isBlank
:跟踪以 StringUtils 结尾的类中的 isBlank 方法。 -
trace *StringUtils isBlank params[0].length==1
:跟踪以 StringUtils 结尾的类中的 isBlank 方法,且方法第一个入参长度为1. -
trace *StringUtils isBlank '#cost>100'
:跟踪以 StringUtils 结尾的类中的 isBlank 方法,且方法执行事件大于100ms。 -
trace -E org\\.apache\\.commons\\.lang\\.StringUtils isBlank
:启用正则表达式匹配(默认为通配符匹配)跟踪以 StringUtils 结尾的类中的 isBlank 方法。 -
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
:跟踪 com.test.ClassA 和 org.test.ClassB 中的 method1、method2、method3方法。 -
trace demo.MathGame run -n 5
:跟踪 demo.MathGame 下的 run 方法,执行5次。 -
trace demo.MathGame run --skipJDKMethod false
:跟踪 demo.MathGame 下的 run 方法 ,不跳过JDK 方法跟踪(默认情况下是跳过的)。 -
trace javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
:使用 --exclude-class-pattern 参数排除掉指定的 com.demo.TestFilter 类。 -
trace OuterClass$InnerClass *
:跟踪符合ognl 表达式 的类和方法。
jad
jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码。
USAGE:
jad [--classLoaderClass <value>] [-c <value>] [-h] [--hideUnicode] [--lineNumber <value>] [-E] [
--source-only] class-pattern [method-name]
SUMMARY:
Decompile class
OPTIONS:
--classLoaderClass <value> The class name of the special class's classLoader.
-c, --code <value> The hash code of the special class's classLoader
-h, --help this help
--hideUnicode hide unicode, default value false
--lineNumber <value> Output source code contins line number, default value true
-E, --regex Enable regular expression to match (wildcard matching by default)
--source-only Output source code only
<class-pattern> Class name pattern, use either '.' or '/' as separator
<method-name> method name pattern, decompile a specific method instead of the w
hole class
示例:
-
jad java.lang.String
: 将String.class 反编译成 String.java -
jad --source-only java.lang.String
:只显示源码
mc
编译.java文件生成.class。
USAGE:
mc [-c <value>] [--classLoaderClass <value>] [-d <value>] [--encoding <value>] [-h] sourcefiles.
..
SUMMARY:
Memory compiler, compiles java files into bytecode and class files in memory.
OPTIONS:
-c, --classloader <value> The hash code of the special ClassLoader
--classLoaderClass <value> The class name of the special class's classLoader.
-d, --directory <value> Sets the destination directory for class files
--encoding <value> Source file encoding
-h, --help this help
<sourcefiles> source files
示例:
-
mc /tmp/Test.java
:编译目标文件到Arthas目录。 -
mc -c 327a647b /tmp/Test.java
:编译目标文件到Arthas目录 ,指定类加载器。 -
mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java
:编译目标文件到指定输出目录。
retransform
加载外部的.class文件,实现热更新。
USAGE:
retransform [-c <value>] [--classLoaderClass <value>] [--classPattern <value>] [-d <value>] [--d
eleteAll] [-h] [--limit <value>] [-l] [classfilePaths...]
SUMMARY:
Retransform classes. @see Instrumentation#retransformClasses(Class...)
OPTIONS:
-c, --classloader <value> classLoader hashcode
--classLoaderClass <value> The class name of the special class's classLoader.
--classPattern <value> trigger retransform matched classes by class pattern.
-d, --delete <value> delete retransform entry by id.
--deleteAll delete all retransform entries.
-h, --help this help
--limit <value> The limit of dump classes size, default value is 50
-l, --list list all retransform entry.
<classfilePaths> .class file paths
示例:
-
retransform /tmp/Test.class
:热更新Test.class文件 -
retransform -l
:查看所有被热更新的文件,每执行一次热更新就生成一条记录。 -
retransform -d 1
:删除指定的热更新 。 -
retransform --deleteAll
:删除所有热更新。 -
retransform --classPattern demo.*
:触发热更新
dump
dump 命令将 JVM 中实际运行的 class 的 byte code dump 到指定目录,适用批量下载指定包目录的 class 字节码的场景。
USAGE:
dump [--classLoaderClass <value>] [-c <value>] [-d <value>] [-h] [-l <value>] [-E] class-pattern
SUMMARY:
Dump class byte array from JVM
OPTIONS:
--classLoaderClass <value> The class name of the special class's classLoader.
-c, --code <value> The hash code of the special class's classLoader
-d, --directory <value> Sets the destination directory for class files
-h, --help this help
-l, --limit <value> The limit of dump classes size, default value is 50
-E, --regex Enable regular expression to match (wildcard matching by default)
<class-pattern> Class name pattern, use either '.' or '/' as separator
示例:
-
dump java.lang.String
: dump 文件到默认目录 -
dump -d /tmp/output java.lang.String
:设置dump文件输出目录为 /tmp/output -
dump java/lang//String
:同dump java.lang.String
-
dump *StringUtils
:通配符匹配,dump 所有全路径以 StringUtils 结尾的类,可以是不同包名下的 StringUtils 类。 -
dump -E java\\.lang\\.String
:开启正则匹配
sm
“Search-Method” 的简写,这个命令能搜索出已经加载了的 Class 的方法信息。,只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
USAGE:
sm [-c <value>] [--classLoaderClass <value>] [-d] [-h] [-n <value>] [-E] class-pattern [method-p
attern]
SUMMARY:
Search the method of classes loaded by JVM
OPTIONS:
-c, --classloader <value> The hash code of the special class's classLoader
--classLoaderClass <value> The class name of the special class's classLoader.
-d, --details Display the details of method
-h, --help this help
-n, --limits <value> Maximum number of matching classes (100 by default)
-E, --regex Enable regular expression to match (wildcard matching by default)
<class-pattern> Class name pattern, use either '.' or '/' as separator
<method-pattern> Method name pattern
示例:
-
sm java.lang.String
:显示 String 类的所有方法。 -
sm -d java.lang.String
:显示 String 类的所有方法及详情。 -
sm -d java/lang/String
:同sm -d java.lang.String
。
monitor
对匹配 class-pattern/method-pattern/condition-express的类、方法的调用进行监控。
USAGE:
monitor [-b] [-c <value>] [--exclude-class-pattern <value>] [-h] [-n <value>] [--listenerId <val
ue>] [-m <value>] [-E] [-v] class-pattern method-pattern [condition-express]
SUMMARY:
Monitor method execution statistics, e.g. total/success/failure count, average rt, fail rate, etc.
OPTIONS:
-b, --before Evaluate the condition-express before method invoke
-c, --cycle <value> The monitor interval (in seconds), 60 seconds by default
--exclude-class-pattern <va exclude class name pattern, use either '.' or '/' as separator
lue>
-h, --help this help
-n, --limits <value> Threshold of execution times
--listenerId <value> The special listenerId
-m, --maxMatch <value> The maximum of matched class.
-E, --regex Enable regular expression to match (wildcard matching by default)
-v, --verbose Enables print verbose information, default value false.
<class-pattern> Path and classname of Pattern Matching
<method-pattern> Method of Pattern Matching
<condition-express> Conditional expression in ognl style, for example:
TRUE : 1==1
TRUE : true
FALSE : false
TRUE : 'params.length>=0'
FALSE : 1==2
'#cost>100'
示例:
-
monitor org.apache.commons.lang.StringUtils isBlank
:监视 StringUtils 类的 isBlank 方法。 -
monitor org.apache.commons.lang.StringUtils isBlank -c 5
:监视间隔设置为5s,默认为60s -
monitor org.apache.commons.lang.StringUtils isBlank params[0]!=null
:计算条件表达式 params[0]!=null 过滤统计结果(方法执行完毕之后) -
monitor -b org.apache.commons.lang.StringUtils isBlank params[0]!=null
:计算条件表达式 params[0]!=null 过滤统计结果(方法执行完毕之前)
watch
观察指定函数的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看。支持调用前监视、异常后监视、调用后监视、成功调用后监视,默认启用调用后监视
USAGE:
watch [-b] [-e] [--exclude-class-pattern <value>] [-x <value>] [-f] [-h] [-n <value>] [--listene
rId <value>] [-m <value>] [-E] [-M <value>] [-s] [-v] class-pattern method-pattern [express] [cond
ition-express]
SUMMARY:
Display the input/output parameter, return object, and thrown exception of specified method invo
cation
The express may be one of the following expression (evaluated dynamically):
target : the object
clazz : the object's class
method : the constructor or method
params : the parameters array of method
params[0..n] : the element of parameters array
returnObj : the returned object of method
throwExp : the throw exception of method
isReturn : the method ended by return
isThrow : the method ended by throwing exception
#cost : the execution time in ms of method invocation
OPTIONS:
-b, --before Watch before invocation
-e, --exception Watch after throw exception
--exclude-class-pattern <va exclude class name pattern, use either '.' or '/' as separator
lue>
-x, --expand <value> Expand level of object (1 by default), the max value is 4
-f, --finish Watch after invocation, enable by default
-h, --help this help
-n, --limits <value> Threshold of execution times
--listenerId <value> The special listenerId
-m, --maxMatch <value> The maximum of matched class.
-E, --regex Enable regular expression to match (wildcard matching by default)
-M, --sizeLimit <value> Upper size limit in bytes for the result (10 * 1024 * 1024 by def
ault)
-s, --success Watch after successful invocation
-v, --verbose Enables print verbose information, default value false.
<class-pattern> The full qualified class name you want to watch
<method-pattern> The method name you want to watch
<express> The content you want to watch, written by ognl. Default value is
'{params, target, returnObj}'
Examples:
params
params[0]
'params[0]+params[1]'
'{params[0], target, returnObj}'
returnObj
throwExp
target
clazz
method
<condition-express> Conditional expression in ognl style, for example:
TRUE : 1==1
TRUE : true
FALSE : false
TRUE : 'params.length>=0'
FALSE : 1==2
'#cost>100'
示例:
watch org.apache.commons.lang.StringUtils isBlank
-
watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj, throwExp}' -x 2
:使用ognl指定监视内容,并且指定输出结果的属性遍历深度为2,默认为 1,最大值是 4。 -
watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
:排查指定类名。
vmtool
vmtool 利用JVMTI接口,实现查询内存对象,强制 GC 等功能。
使用案例
接口响应耗时太久
1、启动 Arthas 附加到目标进程。
2、使用 trace targetClass targetMethod
命令监控方法耗时。如果要专注业务代码的耗时可以增加--skipJDKMethod true
参数跳过JDK方法。
3、trace 命令会将耗时最长的方法高亮显示,此时可以使用jad targetClass --source-only
命令反编译出类文件,查看具体的逻辑代码。
线上调试
有时候需要调试某个接口,但是又还没有做日志,无法获得接口的返回值,此时就可以使用Arthas。
1、启动 Arthas 附加到目标进程。
2、使用watch targetClass targetMethod '{params, target, returnObj, throwExp}' -x 2
命令监视目标方法的参数、返回值以及异常信息。
3、根据返回结果结合代码判断逻辑是否合理。
4、使用jad --source-only targetClass > outputDirectory/targetClass.java
反编译出目标类。然后修改代码执行逻辑,最后使用mc outputDirectory/targetClass.java -d ouputDirectory
将修改完的文件重新编译成class文件。
使用mc命令来编译jad的反编译的代码有可能失败。可以在本地修改代码,编译好后再上传到服务器上。有的服务器不允许直接上传文件,可以使用base64命令来绕过。
5、使用 retransform targerClass
加载外部class文件热更新。(
使用 retransform 更新的文件不允许新增加 field/method;正在执行的函数,没有退出不能生效
6、重复步骤 2,3,4,5直至完成调试。