阅读 3365

万字长文!你还敢说你看不懂阿里开源Java神器Arthas?

大家好,我是爱吃鱼的程序员,一个渴望在互联网行业做到C位的程序员。可柔可刚,点赞则柔,白嫖则刚!看完记得给我来个三连哦!欢迎私信!

java排查神器Arthas -日常用法分析

在这里插入图片描述

前言

有时候线上出现问题,我们需要迫切的找寻解决方法,加日志再上线?查看修改的功能是否成功上线?现在有了Arthas一切都是那么简单。 我们看下官网的描述: Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。

  1. 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
  2. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  3. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  4. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  5. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  6. 是否有一个全局视角来查看系统的运行状况?
  7. 有什么办法可以监控到JVM的实时运行状态?
  8. 怎么快速定位应用的热点,生成火焰图? Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

学习

推荐 按照官方文档结合在线教程。本文档记录一下日常的用法,便于快速查找。

  1. 官方文档
  2. 在线教程
  3. ognl表达式

日常用法

wget https://arthas.aliyun.com/arthas-boot.jar 快速下载

1. 监控方法调用 monitor/watch/trace相关

请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 stop 或将增强过的类执行 reset 命令。

  • monitor——方法执行监控

  • watch——方法执行数据观测

  • trace——方法内部调用路径,并输出方法路径上的每个节点上耗时

  • stack——输出当前方法被调用的调用路径

  • tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

watch

让你能方便的观察到指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看。

参数:

class-pattern 类名表达式匹配

method-pattern 方法名表达式匹配

express 观察表达式

condition-express 条件表达式

-b 在方法调用之前观察

-e 在方法异常之后观察

-s 在方法返回之后观察

-f 在方法结束之后(正常返回和异常返回)观察 默认开启

-E 开启正则表达式匹配,默认为通配符匹配

-x 指定输出结果的属性遍历深度,默认为 1

-n 执行的次数

特别说明:

  • watch 命令定义了4个观察事件点,即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后

  • 4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出

  • 这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参

  • 当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在

  • -x 代表输出结果的深度 ,默认为 1

使用参考

  • 常规用法 watch class method {params,returnObj} -x 1 '#cost>200'

    观察表达式 { } 可以包裹结果集 , 分割。输出的表达式变量定义 params 代表参数数组 ,returnObj代表返回值 过滤耗时大于200ms的

  • 特殊用法

    1.调用第一个参数的方法或属性

    watch class method "{params[0].length()}" -x 1

    watch class method "{params[0].{ #this.length()}}" -x 1

    2.按照条件过滤

    watch class method "{params[0].{?#this.length()>7}}" -x 1

    字符串长度 > 7 才会输出 params[0] 的值

    3.过滤后统计

    watch class method "{params[0].{?#this.length()>9}.size()}" -x 1

trace

trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。

参数说明

class-pattern 类名表达式匹配

method-pattern 方法名表达式匹配

condition-express 条件表达式

-E 开启正则表达式匹配,默认为通配符匹配

-n 命令执行次数

#cost 方法执行耗时

使用参考

1.常规用法

trace class method '#cost>100' -n 1 过滤大于100ms的调用链,只输出一次

2.特殊用法

trace命令只会trace匹配到的函数里的子调用,并不会向下trace多层。因为trace代价比较贵的,多层trace可能会导致最终要trace的类和函数非常多。

动态trace

3.3.0 版本后支持。 打开终端1,trace run函数,可以看到打印出 listenerId: 1:

[arthas@59161]$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 112 ms, listenerId: 1
`---ts=2020-07-09 16:48:11;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[1.389634ms] demo.MathGame:run()
        `---[0.123934ms] demo.MathGame:primeFactors() #24 [throws Exception]
复制代码

现在想要深入子函数primeFactors,可以打开一个新终端2,使用telnet localhost 3658连接上arthas,再trace primeFactors时,指定listenerId

再查看终端1,可以发现trace的结果增加了一层,打印了primeFactors函数里的内容

`---ts=2020-07-09 16:49:29;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[0.492551ms] demo.MathGame:run()
        `---[0.113929ms] demo.MathGame:primeFactors() #24 [throws Exception]
            `---[0.061462ms] demo.MathGame:primeFactors()
                `---[0.001018ms] throw:java.lang.IllegalArgumentException() #46
复制代码

通过指定listenerId的方式动态trace,可以不断深入。另外 watch/tt/monitor等命令也支持类似的功能。

tt

方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。

watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高,因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。

这个时候如果能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。

于是乎,TimeTunnel 命令就诞生了。

参数说明:

-n 执行次数

#cost 过滤耗时

-t tt 命令有很多个主参数,-t 就是其中之一。这个参数的表明希望记录下类 *Test 的 print 方法的每次执行情况。

-s 可以跟条件表达式 进行筛选

-l 列出所有的记录

记录说明 |表格字段 |字段解释| |--|--| |INDEX |时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。| | TIMESTAMP |方法执行的本机时间,记录了这个时间片段所发生的本机时间| | COST(ms) |方法执行的耗时| |IS-RET |方法是否以正常返回的形式结束| |IS-EXP |方法是否以抛异常的形式结束| |OBJECT |执行对象的hashCode(),注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体| |CLASS |执行的类名| |METHOD |执行的方法名|

使用参考

tt -t class method '#cost>100'

 INDEX   TIMESTAMP            COST(ms)  IS-RET  IS-EXP   OBJECT         CLASS                          METHOD
-------------------------------------------------------------------------------------------------------------------------------------
 1000    2018-12-04 11:15:38  1.096236  false   true     0x4b67cf4d     MathGame                       primeFactors
 1001    2018-12-04 11:15:39  0.191848  false   true     0x4b67cf4d     MathGame                       primeFactors
 1002    2018-12-04 11:15:40  0.069523  false   true     0x4b67cf4d     MathGame                       primeFactors
 1003    2018-12-04 11:15:41  0.186073  false   true     0x4b67cf4d     MathGame                       primeFactors
 1004    2018-12-04 11:15:42  17.76437  true    false    0x4b67cf4d     MathGame 
复制代码

查看调用信息 对于具体一个时间片的信息而言,你可以通过 -i 参数后边跟着对应的 INDEX 编号查看到他的详细信息。 tt -i 1003

$ tt -i 1003
 INDEX            1003
 GMT-CREATE       2018-12-04 11:15:41
 COST(ms)         0.186073
 OBJECT           0x4b67cf4d
 CLASS            demo.MathGame
 METHOD           primeFactors
 IS-RETURN        false
 IS-EXCEPTION     true
 PARAMETERS[0]    @Integer[-564322413]
 THROW-EXCEPTION  java.lang.IllegalArgumentException: number is: -564322413, need >= 2
                      at demo.MathGame.primeFactors(MathGame.java:46)
                      at demo.MathGame.run(MathGame.java:24)
                      at demo.MathGame.main(MathGame.java:16)
 
Affect(row-cnt:1) cost in 11 ms.
复制代码

tt -l 查看我们现有的记录

$ tt -l
 INDEX   TIMESTAMP            COST(ms)  IS-RET  IS-EXP   OBJECT         CLASS                          METHOD
-------------------------------------------------------------------------------------------------------------------------------------
 1000    2018-12-04 11:15:38  1.096236  false   true     0x4b67cf4d     MathGame                       primeFactors
 1001    2018-12-04 11:15:39  0.191848  false   true     0x4b67cf4d     MathGame                       primeFactors
 1002    2018-12-04 11:15:40  0.069523  false   true     0x4b67cf4d     MathGame                       primeFactors
 1003    2018-12-04 11:15:41  0.186073  false   true     0x4b67cf4d     MathGame                       primeFactors
 1004    2018-12-04 11:15:42  17.76437  true    false    0x4b67cf4d     MathGame                       primeFactors
                              9
 1005    2018-12-04 11:15:43  0.4776    false   true     0x4b67cf4d     MathGame                       primeFactors
Affect(row-cnt:6) cost in 4 ms.
复制代码

我需要筛选出 primeFactors 方法的调用信息 tt -s

$ tt -s 'method.name=="primeFactors"'
 INDEX   TIMESTAMP            COST(ms)  IS-RET  IS-EXP   OBJECT         CLASS                          METHOD
-------------------------------------------------------------------------------------------------------------------------------------
 1000    2018-12-04 11:15:38  1.096236  false   true     0x4b67cf4d     MathGame                       primeFactors
 1001    2018-12-04 11:15:39  0.191848  false   true     0x4b67cf4d     MathGame                       primeFactors
 1002    2018-12-04 11:15:40  0.069523  false   true     0x4b67cf4d     MathGame                       primeFactors
 1003    2018-12-04 11:15:41  0.186073  false   true     0x4b67cf4d     MathGame                       primeFactors
 1004    2018-12-04 11:15:42  17.76437  true    false    0x4b67cf4d     MathGame                       primeFactors
                              9
 1005    2018-12-04 11:15:43  0.4776    false   true     0x4b67cf4d     MathGame                       primeFactors
Affect(row-cnt:6) cost in 607 ms.
复制代码

stack

很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。

class-pattern 类名表达式匹配

method-pattern 方法名表达式匹配

condition-express 条件表达式

-E 开启正则表达式匹配,默认为通配符匹配

-n 执行次数限制

使用参考

stack demo.MathGame primeFactors ’#cost>5‘ 输出调用链,按照执行时间过滤

stack demo.MathGame primeFactors 'params[0]<0' -n 2 按照条件表达式进行过滤

monitor

参数说明

方法拥有一个命名参数 [c:],意思是统计周期(cycle of output),拥有一个整型的参数值 | 参数名称 | 参数说明 | |--|--| |class-pattern |类名表达式匹配| |method-pattern |方法名表达式匹配| |condition-express |条件表达式| |-E |开启正则表达式匹配,默认为通配符匹配| |-c |统计周期,默认值为120秒| |-b |在方法调用之前计算condition-express|

监控的维度说明 |监控项 |说明| |--|--| |timestamp |时间戳| |class |Java类| |method |方法(构造方法、普通方法)| |total |调用次数| |success |成功次数| |fail |失败次数| |rt |平均RT| |fail-rate |失败率|

使用参考

monitor -c 5 demo.MathGame primeFactors 每5秒统计一次

$ monitor -c 5 demo.MathGame primeFactors
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:06:38  demo.MathGame  primeFactors  5      1        4     1.15        80.00%
 
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:06:43  demo.MathGame  primeFactors  5      3        2     42.29       40.00%
 
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:06:48  demo.MathGame  primeFactors  5      3        2     67.92       40.00%
 
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:06:53  demo.MathGame  primeFactors  5      2        3     0.25        60.00%
 
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:06:58  demo.MathGame  primeFactors  1      1        0     0.45        0.00%
 
 timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------
 2018-12-03 19:07:03  demo.MathGame  primeFactors  2      2        0     3182.72     0.00%

复制代码

计算条件表达式过滤统计结果(方法执行完毕之后)

monitor -c 5 demo.MathGame primeFactors "params[0] <= 2"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 19 ms, listenerId: 5
 timestamp            class          method         total  success  fail  avg-rt(ms)  fail-rate        
-----------------------------------------------------------------------------------------------
 2020-09-02 09:42:36  demo.MathGame  primeFactors    5       3       2      0.09       40.00%           
 
 timestamp            class          method         total  success  fail  avg-rt(ms)  fail-rate        
----------------------------------------------------------------------------------------------
 2020-09-02 09:42:41  demo.MathGame  primeFactors    5       2       3      0.11       60.00%           
 
 timestamp            class          method         total  success  fail  avg-rt(ms)  fail-rate        
----------------------------------------------------------------------------------------------
 2020-09-02 09:42:46  demo.MathGame  primeFactors    5       1       4      0.06       80.00%           
 
 timestamp            class          method         total  success  fail  avg-rt(ms)  fail-rate        
----------------------------------------------------------------------------------------------
 2020-09-02 09:42:51  demo.MathGame  primeFactors    5       1       4      0.12       80.00%           
 
 timestamp            class          method         total  success  fail  avg-rt(ms)  fail-rate        
----------------------------------------------------------------------------------------------
 2020-09-02 09:42:56  demo.MathGame  primeFactors    5       3       2      0.15       40.00%           

复制代码

2.jvm相关

  • dashboard——当前系统的实时数据面板

  • thread——查看当前 JVM 的线程堆栈信息

  • jvm——查看当前 JVM 的信息

  • sysprop——查看和修改JVM的系统属性

  • sysenv——查看JVM的环境变量

  • vmoption——查看和修改JVM里诊断相关的option

  • perfcounter——查看当前 JVM 的Perf Counter信息

  • logger——查看和修改logger

  • getstatic——查看类的静态属性

  • ognl——执行ognl表达式

  • mbean——查看 Mbean 的信息

  • heapdump——dump java heap, 类似jmap命令的heap dump功能

dashboard

当前系统的实时数据面板,按 ctrl+c 退出。

命令

dashboard -i 5000 -n 10

-i 刷新实时数据的时间间隔 (ms),默认5000ms -n 刷新数据的次数

数据说明

  • ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应。
  • NAME: 线程名
  • GROUP: 线程组名
  • PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
  • STATE: 线程的状态
  • CPU%: 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10%
  • DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为秒
  • TIME: 线程运行总CPU时间,数据格式为分:秒
  • INTERRUPTED: 线程当前的中断位状态
  • DAEMON: 是否是daemon线程

在这里插入图片描述

thread

查看当前线程信息,查看线程的堆栈

参数名称参数说明
id线程id
-n指定最忙的前N个线程并打印堆栈
-b找出当前阻塞其他线程的线程
-i指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200
--all显示所有匹配的线程
--state查看指定状态的线程

常用操作

thread -b, 找出当前阻塞其他线程的线程 有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成的。 为了排查这类问题, arthas提供了thread -b, 一键找出那个罪魁祸首

thread -i 1000 : 统计最近1000ms内的线程CPU时间。

thread -n 3 -i 1000 : 列出1000ms内最忙的3个线程栈

thread --state WAITING 列出等待态的线程

jvm

查看当前JVM信息

使用参考

$ jvm
RUNTIME
--------------------------------------------------------------------------------------------------------------
 MACHINE-NAME                   37@ff267334bb65
 JVM-START-TIME                 2020-07-23 07:50:36
 MANAGEMENT-SPEC-VERSION        1.2
 SPEC-NAME                      Java Virtual Machine Specification
 SPEC-VENDOR                    Oracle Corporation
 SPEC-VERSION                   1.8
 VM-NAME                        Java HotSpot(TM) 64-Bit Server VM
 VM-VENDOR                      Oracle Corporation
 VM-VERSION                     25.201-b09
 INPUT-ARGUMENTS                []
 CLASS-PATH                     demo-arthas-spring-boot.jar
 BOOT-CLASS-PATH                /usr/lib/jvm/java-8-oracle/jre/lib/resources.jar:/usr/lib/jvm/java-8-oracle/j
                                re/lib/rt.jar:/usr/lib/jvm/java-8-oracle/jre/lib/sunrsasign.jar:/usr/lib/jvm/
                                java-8-oracle/jre/lib/jsse.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jce.jar:/us
                                r/lib/jvm/java-8-oracle/jre/lib/charsets.jar:/usr/lib/jvm/java-8-oracle/jre/l
                                ib/jfr.jar:/usr/lib/jvm/java-8-oracle/jre/classes
 LIBRARY-PATH                   /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

--------------------------------------------------------------------------------------------------------------
 CLASS-LOADING
--------------------------------------------------------------------------------------------------------------
 LOADED-CLASS-COUNT             7529
 TOTAL-LOADED-CLASS-COUNT       7529
 UNLOADED-CLASS-COUNT           0
 IS-VERBOSE                     false

--------------------------------------------------------------------------------------------------------------
 COMPILATION
--------------------------------------------------------------------------------------------------------------
 NAME                           HotSpot 64-Bit Tiered Compilers
 TOTAL-COMPILE-TIME             14921(ms)

--------------------------------------------------------------------------------------------------------------
 GARBAGE-COLLECTORS
--------------------------------------------------------------------------------------------------------------
 PS Scavenge                            name : PS Scavenge                                                                             
 [count/time (ms)]                      collectionCount : 7                                                                            
                                        collectionTime : 68                                                                            
                                                                                                                                       
 PS MarkSweep                           name : PS MarkSweep                                                                            
 [count/time (ms)]                      collectionCount : 1                                                                            
                                        collectionTime : 47 

--------------------------------------------------------------------------------------------------------------
 MEMORY-MANAGERS
--------------------------------------------------------------------------------------------------------------
 CodeCacheManager               Code Cache

 Metaspace Manager              Metaspace
                                Compressed Class Space

 Copy                           Eden Space
                                Survivor Space

 MarkSweepCompact               Eden Space
                                Survivor Space
                                Tenured Gen

--------------------------------------------------------------------------------------------------------------
 MEMORY
--------------------------------------------------------------------------------------------------------------
 HEAP-MEMORY-USAGE                      init : 268435456(256.0 MiB)                                                                    
 [memory in bytes]                      used : 18039504(17.2 MiB)                                                                      
                                        committed : 181403648(173.0 MiB)                                                               
                                        max : 3817865216(3.6 GiB)                                                                      
                                                                                                                                       
 NO-HEAP-MEMORY-USAGE                   init : 2555904(2.4 MiB)                                                                        
 [memory in bytes]                      used : 33926216(32.4 MiB)                                                                      
                                        committed : 35176448(33.5 MiB)                                                                 
                                        max : -1(-1 B)  

--------------------------------------------------------------------------------------------------------------
 OPERATING-SYSTEM
--------------------------------------------------------------------------------------------------------------
 OS                             Linux
 ARCH                           amd64
 PROCESSORS-COUNT               3
 LOAD-AVERAGE                   29.53
 VERSION                        4.15.0-52-generic

--------------------------------------------------------------------------------------------------------------
 THREAD
--------------------------------------------------------------------------------------------------------------
 COUNT                          30
 DAEMON-COUNT                   24
 PEAK-COUNT                     31
 STARTED-COUNT                  36
 DEADLOCK-COUNT                 0

--------------------------------------------------------------------------------------------------------------
 FILE-DESCRIPTOR
--------------------------------------------------------------------------------------------------------------
 MAX-FILE-DESCRIPTOR-COUNT      1048576
 OPEN-FILE-DESCRIPTOR-COUNT     100
Affect(row-cnt:0) cost in 88 ms.
复制代码

THREAD相关

  • COUNT: JVM当前活跃的线程数

  • DAEMON-COUNT: JVM当前活跃的守护线程数

  • PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数

  • STARTED-COUNT: 从JVM启动开始总共启动过的线程次数

  • DEADLOCK-COUNT: JVM当前死锁的线程数

文件描述符相关

  • MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数

  • OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数

heapdump

dump java heap, 类似jmap命令的heap dump功能。

使用参考

dump到指定文件

[arthas@58205]$ heapdump /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created
复制代码

只dump live对象

[arthas@58205]$ heapdump --live /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created
复制代码

dump到临时文件

[arthas@58205]$ heapdump
Dumping heap to /var/folders/my/wy7c9w9j5732xbkcyt1mb4g40000gp/T/heapdump2019-09-03-16-385121018449645518991.hprof...
Heap dump file created
复制代码

sysprop 和 sysenv

sysprop 查看和修改当前JVM的系统属性(System Property) sysenv 查看当前JVM的环境属性(System Environment Variables)

sysprop 和 sysenv使用方式类似

使用参考

$ sysprop
 KEY                                                  VALUE
-------------------------------------------------------------------------------------------------------------------------------------
 java.runtime.name                                    Java(TM) SE Runtime Environment
 sun.boot.library.path                                /Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/jre/lib
 java.vm.version                                      25.51-b03
 user.country.format                                  CN
 gopherProxySet                                       false
 java.vm.vendor                                       Oracle Corporation
 java.vendor.url                                      http://java.oracle.com/
 path.separator                                       :
 java.vm.name                                         Java HotSpot(TM) 64-Bit Server VM
 file.encoding.pkg                                    sun.io
 user.country                                         US
 sun.java.launcher                                    SUN_STANDARD
 sun.os.patch.level                                   unknown
 java.vm.specification.name                           Java Virtual Machine Specification
 user.dir                                             /private/var/tmp
 java.runtime.version                                 1.8.0_51-b16
 java.awt.graphicsenv                                 sun.awt.CGraphicsEnvironment
 java.endorsed.dirs                                   /Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/jre/lib/endors
                                                      ed
 os.arch                                              x86_64
 java.io.tmpdir                                       /var/folders/2c/tbxwzs4s4sbcvh7frbcc7n000000gn/T/
 line.separator

 java.vm.specification.vendor                         Oracle Corporation
 os.name                                              Mac OS X
 sun.jnu.encoding                                     UTF-8
 java.library.path                                    /Users/wangtao/Library/Java/Extensions:/Library/Java/Extensions:/Network/Libra
                                                      ry/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
 sun.nio.ch.bugLevel
 java.specification.name                              Java Platform API Specification
 java.class.version                                   52.0
 sun.management.compiler                              HotSpot 64-Bit Tiered Compilers
 os.version                                           10.12.6
 user.home                                            /Users/wangtao
 user.timezone                                        Asia/Shanghai
 java.awt.printerjob                                  sun.lwawt.macosx.CPrinterJob
 file.encoding                                        UTF-8
 java.specification.version                           1.8
 user.name                                            wangtao
 java.class.path                                      .
 java.vm.specification.version                        1.8
 sun.arch.data.model                                  64
复制代码

查看单个属性 支持通过TAB键自动补全

$ sysprop java.version
java.version=1.8.0_51
复制代码

修改单个属性

$ sysprop user.country
user.country=US
$ sysprop user.country CN
Successfully changed the system property.
user.country=CN
复制代码

logger

查看logger信息,更新logger level

使用参考

查看所有logger信息

[arthas@2062]$ logger
 name                                   ROOT
 class                                  ch.qos.logback.classic.Logger
 classLoader                            sun.misc.Launcher$AppClassLoader@2a139a55
 classLoaderHash                        2a139a55
 level                                  INFO
 effectiveLevel                         INFO
 additivity                             true
 codeSource                             file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
 appenders                              name            CONSOLE
                                        class           ch.qos.logback.core.ConsoleAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        target          System.out
                                        name            APPLICATION
                                        class           ch.qos.logback.core.rolling.RollingFileAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        file            app.log
                                        name            ASYNC
                                        class           ch.qos.logback.classic.AsyncAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        appenderRef     [APPLICATION]
复制代码

appenders的信息里,可以看到

  • CONSOLE logger的target是System.out

  • APPLICATION logger是RollingFileAppender,它的file是app.log

  • ASYNC它的appenderRef是APPLICATION,即异步输出到文件里

查看指定的logger信息

按名字查找

[arthas@2062]$ logger -n org.springframework.web
 name                                   org.springframework.web
 class                                  ch.qos.logback.classic.Logger
 classLoader                            sun.misc.Launcher$AppClassLoader@2a139a55
 classLoaderHash                        2a139a55
 level                                  null
 effectiveLevel                         INFO
 additivity                             true
 codeSource                             file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar

复制代码

指定classloader查找

注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode

如果你使用-c,你需要手动输入hashcode:-c <hashcode>

[arthas@2062]$ logger -c 2a139a55
 name                                   ROOT
 class                                  ch.qos.logback.classic.Logger
 classLoader                            sun.misc.Launcher$AppClassLoader@2a139a55
 classLoaderHash                        2a139a55
 level                                  DEBUG
 effectiveLevel                         DEBUG
 additivity                             true
 codeSource                             file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
 appenders                              name            CONSOLE
                                        class           ch.qos.logback.core.ConsoleAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        target          System.out
                                        name            APPLICATION
                                        class           ch.qos.logback.core.rolling.RollingFileAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        file            app.log
                                        name            ASYNC
                                        class           ch.qos.logback.classic.AsyncAppender
                                        classLoader     sun.misc.Launcher$AppClassLoader@2a139a55
                                        classLoaderHash 2a139a55
                                        appenderRef     [APPLICATION]

复制代码

更新 logger level

[arthas@2062]$ logger --name ROOT --level debug
update logger level success.
复制代码

指定classloader更新 logger level

默认情况下,logger命令会在SystemClassloader下执行,如果应用是传统的war应用,或者spring boot fat jar启动的应用,那么需要指定classloader。

[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
复制代码

3. class/classloader相关

jad

反编译指定已加载类的源码

jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;

  • 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便

  • 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解

使用参考

编译java.lang.String

$ jad java.lang.String
 
ClassLoader:
 
Location:
 
/*
* Decompiled with CFR 0_132.
*/
package java.lang;
 
import java.io.ObjectStreamField;
...
public final class String
implements Serializable,
Comparable<String>,
CharSequence {
    private final char[] value;
    private int hash;
    private static final long serialVersionUID = -6849794470754667710L;
    private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
    public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
 
    public String(byte[] arrby, int n, int n2) {
        String.checkBounds(arrby, n, n2);
        this.value = StringCoding.decode(arrby, n, n2);
    }
...
复制代码

反编译时只显示源代码

默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。

$ jad --source-only demo.MathGame
/*
 * Decompiled with CFR 0_132.
 */
package demo;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class MathGame {
    private static Random random = new Random();
    public int illegalArgumentCount = 0;
...
复制代码

反编译指定的函数

$ jad demo.MathGame main

4.后台执行

arthas中的后台异步任务,使用了仿linux系统任务相关的命令。

1.使用&在后台执行任务 比如希望执行后台执行trace命令,那么调用下面命令

trace Test t & 这时命令在后台执行,可以在console中继续执行其他命令。

2.通过jobs查看任务 如果希望查看当前有哪些arthas任务在执行,可以执行jobs命令,执行结果如下

kill job-id 可以杀死指定任务

$ jobs
[10]*
       Stopped           watch com.taobao.container.Test test "params[0].{? #this.name == null }" -x 2
       execution count : 19
       start time      : Fri Sep 22 09:59:55 CST 2017
       timeout date    : Sat Sep 23 09:59:55 CST 2017
       session         : 3648e874-5e69-473f-9eed-7f89660b079b (current)
复制代码

可以看到目前有一个后台任务在执行。

  • job id是10, * 表示此job是当前session创建
  • 状态是Stopped
  • execution count是执行次数,从启动开始已经执行了19次
  • timeout date是超时的时间,到这个时间,任务将会自动超时退出

任务转到前台执行 fg <job-id> 可以把对应的任务转到前台继续执行。 bg <job-id>可以把对应的任务在后台继续执行

任务输出重定向

可通过>或者>>将任务输出结果输出到指定的文件中,可以和&一起使用,实现arthas命令的后台异步任务

$ trace Test t >> test.out &

今天的你多努力一点,明天的C位就是你! 一起学习成为 C位程序员。💋 微信公众号已开启,【C位程序员】,没关注的同学们记得关注哦!