arthas常用命令

文档

Arthas 用户文档

启动

1
2
wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar

命令

dashboard

查看当前java进程的实时数据面板

1
dashboard

thread

查看当前线程信息

1
thread

classloader

类加载器信息

按类加载类型查看统计信息

1
classloader

查看ClassLoader统计信息和实例hash

1
classloader -l

查看ClassLoader的继承树

1
classloader -t

ognl

执行ognl表达式

执行静态方法

1
ognl '@java.lang.Math@abs(-1)'

获取静态变量

1
ognl '@java.lang.System@out'

执行对象方法

1
ognl '#date=new java.util.Date(),#date.setTime(1),#date.getTime()'

指定ClassLoader执行静态方法

ognl默认使用SystemClassLoader,非默认加载器加载的Class无法读取,需要通过sc -d com.sz.Test(推荐)或者classloader -l命令获取加载该CLass的类加载器的hash后,指定hash执行静态方法

1
ognl -c 439f5b3d '@com.sz.Test@log.info("test")'

sc

查看JVM已加载的类信息

模糊搜索已加载的类

1
sc *service*

打印类的详细信息

1
sc -d com.sz.Test

jad

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

反编译输出到文件

1
jad com.sz.Test > /opt/Test.java

monitor

方法执行监控

每5秒输出方法的访问次数

1
monitor -c 5 com.sz.Test test

watch

输出方法出参和返回值

1
watch com.sz.Test test "{params,returnObj}" -x 3

条件表达式过滤

1
watch com.sz.Test test "{params,returnObj}" "params[1]==5" -x 3

异常输出

1
watch com.sz.Test test "{params[0],throwExp}" -e -x 2

火焰图

  1. 启动profiler
    1
    2
    3
    # 基于CPU使用率采样(适用于CPU密集型)
    $ profiler start
    Started [cpu] profiling
1
2
3
# 基于样本采样,可估算耗时(适用于IO密集型)
$ profiler start -e wall
Started [wall] profiling
  1. 获取已采集的sample的数量

    1
    2
    $ profiler getSamples
    23
  2. 查看profiler状态

    1
    2
    $ profiler status
    [cpu] profiling is running for 4 seconds
  3. 生成svg格式结果

    1
    2
    3
    $ profiler stop
    profiler output file: /tmp/demo/arthas-output/20191125-135546.svg
    OK

tt

方法执行数据的隧道

记录方法调用的环境现场

1
tt -t com.sz.Test test

输出

1
2
3
 INDEX    TIMESTAMP              COST(ms)    IS-RET   IS-EXP   OBJECT            CLASS     METHOD
---------------------------------------------------------------------------------------------------
1000 2019-04-05 15:49:28 17.526337 true false 0x6c03fb16 Test test

通过环境现场的index获取方法对象

1
tt -i 1000 -w 'target.log.info("hello world")'

Alibaba Arthas实践–获取到Spring Context,然后为所欲为

trace

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

输出耗时大于100ms的调用路径

1
trace org.springframework.web.servlet.DispatcherServlet * '#cost > 100'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Affect(class count: 1 , method count: 44) cost in 356 ms, listenerId: 5
`---ts=2021-03-19 09:39:50;thread_name=http-nio-8088-exec-7;id=64;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@59b98152
`---[527.902147ms] org.springframework.web.servlet.DispatcherServlet:doService()
+---[0.00661ms] org.apache.commons.logging.Log:isDebugEnabled() #889
+---[0.007177ms] org.springframework.web.util.WebUtils:isIncludeRequest() #898
+---[0.006119ms] org.springframework.web.servlet.DispatcherServlet:getWebApplicationContext() #910
+---[min=0.00399ms,max=0.00549ms,total=0.013975ms,count=3] javax.servlet.http.HttpServletRequest:setAttribute() #95
+---[0.004205ms] javax.servlet.http.HttpServletRequest:setAttribute() #911
+---[0.003514ms] javax.servlet.http.HttpServletRequest:setAttribute() #912
+---[0.04213ms] org.springframework.web.servlet.DispatcherServlet:getThemeSource() #913
| `---[0.024214ms] org.springframework.web.servlet.DispatcherServlet:getThemeSource()
| +---[0.004096ms] org.springframework.web.servlet.DispatcherServlet:getWebApplicationContext() #782
| `---[0.004078ms] org.springframework.web.servlet.DispatcherServlet:getWebApplicationContext() #95
+---[0.015018ms] org.springframework.web.servlet.FlashMapManager:retrieveAndUpdate() #916
+---[0.005817ms] org.springframework.web.servlet.FlashMap:<init>() #920
+---[0.003581ms] javax.servlet.http.HttpServletRequest:setAttribute() #921
+---[527.660569ms] org.springframework.web.servlet.DispatcherServlet:doDispatch() #925
| `---[527.641089ms] org.springframework.web.servlet.DispatcherServlet:doDispatch()
| +---[0.00552ms] org.springframework.web.context.request.async.WebAsyncUtils:getAsyncManager() #953
| +---[0.034196ms] org.springframework.web.servlet.DispatcherServlet:checkMultipart() #960
| | `---[0.018654ms] org.springframework.web.servlet.DispatcherServlet:checkMultipart()
| | `---[0.007299ms] org.springframework.web.multipart.MultipartResolver:isMultipart() #1117
| +---[0.344646ms] org.springframework.web.servlet.DispatcherServlet:getHandler() #964
| | `---[0.318626ms] org.springframework.web.servlet.DispatcherServlet:getHandler()
| | +---[min=0.003103ms,max=0.003579ms,total=0.006682ms,count=2] org.apache.commons.logging.Log:isTraceEnabled() #1184
| | `---[min=0.044735ms,max=0.229457ms,total=0.274192ms,count=2] org.springframework.web.servlet.HandlerMapping:getHandler() #1188
| +---[0.005121ms] org.springframework.web.servlet.HandlerExecutionChain:getHandler() #971
| +---[0.044803ms] org.springframework.web.servlet.DispatcherServlet:getHandlerAdapter() #95
| | `---[0.027969ms] org.springframework.web.servlet.DispatcherServlet:getHandlerAdapter()
| | +---[0.004322ms] org.apache.commons.logging.Log:isTraceEnabled() #1225
| | `---[0.006146ms] org.springframework.web.servlet.HandlerAdapter:supports() #1228
| +---[0.003523ms] javax.servlet.http.HttpServletRequest:getMethod() #974
| +---[0.003492ms] org.springframework.web.servlet.HandlerExecutionChain:getHandler() #977
| +---[0.00555ms] org.springframework.web.servlet.HandlerAdapter:getLastModified() #95
| +---[0.003345ms] org.apache.commons.logging.Log:isDebugEnabled() #978
| +---[0.00582ms] org.springframework.web.context.request.ServletWebRequest:<init>() #981
| +---[0.01446ms] org.springframework.web.context.request.ServletWebRequest:checkNotModified() #95
| +---[2.956797ms] org.springframework.web.servlet.HandlerExecutionChain:applyPreHandle() #986
| +---[0.008488ms] org.springframework.web.servlet.HandlerExecutionChain:getHandler() #991
| +---[523.914178ms] org.springframework.web.servlet.HandlerAdapter:handle() #95
| +---[0.005795ms] org.springframework.web.context.request.async.WebAsyncManager:isConcurrentHandlingStarted() #993
| +---[0.044017ms] org.springframework.web.servlet.DispatcherServlet:applyDefaultViewName() #997
| | `---[0.012355ms] org.springframework.web.servlet.DispatcherServlet:applyDefaultViewName()
| +---[0.012352ms] org.springframework.web.servlet.HandlerExecutionChain:applyPostHandle() #998
| +---[0.075111ms] org.springframework.web.servlet.DispatcherServlet:processDispatchResult() #1008
| | `---[0.056069ms] org.springframework.web.servlet.DispatcherServlet:processDispatchResult()
| | +---[0.005093ms] org.apache.commons.logging.Log:isDebugEnabled() #1075
| | +---[0.007475ms] org.springframework.web.context.request.async.WebAsyncUtils:getAsyncManager() #1081
| | +---[0.00442ms] org.springframework.web.context.request.async.WebAsyncManager:isConcurrentHandlingStarted() #95
| | `---[0.00794ms] org.springframework.web.servlet.HandlerExecutionChain:triggerAfterCompletion() #1087
| `---[0.004107ms] org.springframework.web.context.request.async.WebAsyncManager:isConcurrentHandlingStarted() #1018
+---[0.006615ms] org.springframework.web.context.request.async.WebAsyncUtils:getAsyncManager() #928
`---[0.004469ms] org.springframework.web.context.request.async.WebAsyncManager:isConcurrentHandlingStarted() #95

常见问题

需要监控31299 进程,输入 2 回车后,监控到了 1进程 23873