Arthas(阿尔萨斯) — 阿里在线诊断神器

Arthas简介

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。
Arthas 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

Github: https://github.com/alibaba/arthas
文档: https://arthas.aliyun.com/doc/
参考:https://alibaba.github.io/arthas/quick-start.html
演示:https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn
命令列表: https://arthas.aliyun.com/doc/commands.html

测试应用

首先,我们随便来一个测试项目,代码如下:

package cn.appblog.arthas;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author yezhou
 * @version 1.0
 * @date 2020/8/20 10:28
 */
@RestController
public class TestController {

    @GetMapping(value = "test")
    public User abc(Integer integer) {
        if (integer == 0) {
            throw new IllegalArgumentException("参数 0 异常");
        }
        User user = new User();
        user.setName("Joe.Ye");
        user.setAge(integer);
        return user;
    }
}

Arthas服务启动及使用

(1)启动服务

E:\Java-Project\arthas>java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.3.9
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 11908
  [2]: 26932 cn.appblog.arthas.ArthasApplication
2  //选择应用进程
[INFO] Start download arthas from remote server: https://arthas.aliyun.com/download/3.3.9?mirror=aliyun
[INFO] File size: 11.44 MB, downloaded size: 11.20 MB, downloading ...
[INFO] Download arthas success.
[INFO] arthas home: C:\Users\yezhou\.arthas\lib\3.3.9\arthas
[INFO] Try to attach process 11908
Exception in thread "main" java.lang.IllegalArgumentException: Can not find tools.jar under java home: C:\Program Files\Java\jre1.8.0_231, please try to start arthas-boot with full path java. Such as /opt/jdk/bin/java -jar arthas-boot.jar
        at com.taobao.arthas.boot.ProcessUtils.findJavaHome(ProcessUtils.java:222)
        at com.taobao.arthas.boot.ProcessUtils.startArthasCore(ProcessUtils.java:233)
        at com.taobao.arthas.boot.Bootstrap.main(Bootstrap.java:506)

(2)若报如上错误,则以如下方式启动

set JAVA_HOME="C:\Program Files\Java\jdk1.8.0_231\jre"
"C:\Program Files\Java\jdk1.8.0_231\bin\java.exe" -jar arthas-boot.jar

(3)停止服务

java -jar C:\Users\yezhou\.arthas\lib\3.3.9\arthas\arthas-client.jar 127.0.0.1 3658 -c "stop"

(4)命令列表

[arthas@26932]$ help
 NAME         DESCRIPTION
 help         Display Arthas Help
 keymap       Display all the available keymap for the specified connection.
 sc           Search all the classes loaded by JVM
 sm           Search the method of classes loaded by JVM
 classloader  Show classloader info
 jad          Decompile class
 getstatic    Show the static field of a class
 monitor      Monitor method execution statistics, e.g. total/success/failure count, average rt, fail rate, etc.
 stack        Display the stack trace for the specified class and method
 thread       Display thread info, thread stack
 trace        Trace the execution time of specified method invocation.
 watch        Display the input/output parameter, return object, and thrown exception of specified method invocation
 tt           Time Tunnel
 jvm          Display the target JVM information
 perfcounter  Display the perf counter infornation.
 ognl         Execute ognl expression.
 mc           Memory compiler, compiles java files into bytecode and class files in memory.
 redefine     Redefine classes. @see Instrumentation#redefineClasses(ClassDefinition...)
 dashboard    Overview of target jvm's thread, memory, gc, vm, tomcat info.
 dump         Dump class byte array from JVM
 heapdump     Heap dump
 options      View and change various Arthas options
 cls          Clear the screen
 reset        Reset all the enhanced classes
 version      Display Arthas version
 session      Display current session information
 sysprop      Display, and change the system properties.
 sysenv       Display the system env.
 vmoption     Display, and update the vm diagnostic options.
 logger       Print logger info, and update the logger level
 history      Display command history
 cat          Concatenate and print files
 echo         write arguments to the standard output
 pwd          Return working directory name
 mbean        Display the mbean information
 grep         grep command for pipes.
 tee          tee command for pipes.
 profiler     Async Profiler. https://github.com/jvm-profiling-tools/async-profiler
 stop         Stop/Shutdown Arthas server and exit the console.

Arthas命令

sc 命令

命令介绍:该命令是Search-Class英文的缩写,用于查看JVM已加载的类信息

常用参数详情

  • -d: 参数用于输出详细的类相关信息(类全限定名,存放路径,接口,注解,继承父类,类加载器等),支持模糊查询
  • -f: 参数需要配合 -d 命令一起使用, 在上述类信息中加入字段信息,包括权限、类型、名字

例子(使用模糊的方式):

sc -d -f *TestController
[arthas@26932]$ sc -d -f *TestController
 class-info        cn.appblog.arthas.TestController
 code-source       /E:/Java-Project/arthas/target/classes/
 name              cn.appblog.arthas.TestController
 isInterface       false
 isAnnotation      false
 isEnum            false
 isAnonymousClass  false
 isArray           false
 isLocalClass      false
 isMemberClass     false
 isPrimitive       false
 isSynthetic       false
 simple-name       TestController
 modifier          public
 annotation        org.springframework.web.bind.annotation.RestController
 interfaces
 super-class       +-java.lang.Object
 class-loader      +-sun.misc.Launcher$AppClassLoader@18b4aac2
                     +-sun.misc.Launcher$ExtClassLoader@64b8f8f4
 classLoaderHash   18b4aac2
 fields

Affect(row-cnt:1) cost in 18 ms.

其他参数:

  • -E: 开启正则表达式匹配,默认为通配符匹配
  • -c: 类名表达式匹配

sm 命令

命令介绍:该命令是Search-Method英文的缩写,用于查看已加载类的方法信息

常用参数

  • -d: 方法详情

例子:(模糊匹配找到TestController下的abc方法详情)

sm -d *TestController abc
[arthas@26932]$ sm -d *TestController abc
 declaring-class  cn.appblog.arthas.TestController
 method-name      abc
 modifier         public
 annotation       org.springframework.web.bind.annotation.GetMapping
 parameters       java.lang.Integer
 return           cn.appblog.arthas.User
 exceptions
 classLoaderHash  18b4aac2

Affect(row-cnt:1) cost in 17 ms.

非常用参数:

  • -E: 开启正则表达式匹配,默认为通配符匹配
  • -c: 类名表达式匹配

jad 命令

命令介绍:该命令可以反编译出已加载类的源代码,如果没有线下环境,我们可以在线上查看到底哪行代码出问题。

例子:

jad *TestController
[arthas@26932]$ jad *TestController

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
  +-sun.misc.Launcher$ExtClassLoader@64b8f8f4

Location:
/E:/Java-Project/arthas/target/classes/

/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  cn.appblog.arthas.User
 */
package cn.appblog.arthas;

import cn.appblog.arthas.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @GetMapping(value={"test"})
    public User abc(Integer integer) {
        if (integer == 0) {
            throw new IllegalArgumentException("鍙傛暟 0 寮傚父");
        }
        User user = new User();
        user.setName("Joe.Ye");
        user.setAge(integer);
        return user;
    }
}

Affect(row-cnt:1) cost in 860 ms.

tt 命令

tt 命令有点强,使用该命令,会有一个记录表,请求来时,会将请求记录下来,可以进行重放(由 Arthas 启动线程请求)

常用参数:

  • -t: 开启方法监听,记录下TestController中方法abc的调用情况
tt -t *TestController abc
[arthas@26932]$ tt -t *TestController abc
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 110 ms, listenerId: 1
 INDEX  TIMESTAMP           COST(ms)   IS-RET  IS-EXP  OBJECT        CLASS                      METHOD
-----------------------------------------------------------------------------------------------------------------------
 1000   2020-08-20 15:44:32  0.675401   true   false   0x3d4f4fbf    TestController             abc             
 1001   2020-08-20 15:44:45  0.2588     false  true    0x3d4f4fbf    TestController             abc
 1002   2020-08-20 15:45:03  0.049399   true   false   0x3d4f4fbf    TestController             abc             

接下来我们按 Q 或者 Ctrl+C 退出监听。

  • -i: i是指index索引的意思,可以用来找出之前请求的信息
tt -i 1000
[arthas@26932]$ tt -i 1000
 INDEX          1000
 GMT-CREATE     2020-08-20 15:44:32
 COST(ms)       0.675401
 OBJECT         0x3d4f4fbf
 CLASS          cn.appblog.arthas.TestController
 METHOD         abc
 IS-RETURN      true
 IS-EXCEPTION   false
 PARAMETERS[0]  @Integer[20]
 RETURN-OBJ     @User[
                    name=@String[Joe.Ye],
                    age=@Integer[20],
                ]
Affect(row-cnt:1) cost in 9 ms.
[arthas@26932]$ tt -i 1001
 INDEX            1001
 GMT-CREATE       2020-08-20 15:44:45
 COST(ms)         0.2588
 OBJECT           0x3d4f4fbf
 CLASS            cn.appblog.arthas.TestController
 METHOD           abc
 IS-RETURN        false
 IS-EXCEPTION     true
 PARAMETERS[0]    null
 THROW-EXCEPTION  java.lang.NullPointerException
                        at cn.appblog.arthas.TestController.abc(TestController.java:16)
                        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                        at java.lang.reflect.Method.invoke(Method.java:498)
                        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
                        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
                        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
                        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
                        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
                        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
                        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
                        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
                        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
                        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
                        at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
                        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
                        at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
                        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
                        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
                        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
                        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
                        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
                        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
                        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
                        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
                        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
                        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
                        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
                        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
                        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
                        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
                        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                        at java.lang.Thread.run(Thread.java:748)

Affect(row-cnt:1) cost in 12 ms.
  • -l: 找出列表所有请求
tt -l
[arthas@26932]$ tt -l
 INDEX  TIMESTAMP          COST(ms  IS-RE  IS-EXP  OBJECT        CLASS                      METHOD
                           )        T
-----------------------------------------------------------------------------------------------------------------------
 1000   2020-08-20 15:44:32  0.675401  true   false   0x3d4f4fbf    TestController             abc
 1001   2020-08-20 15:44:45  0.2588    false  true    0x3d4f4fbf    TestController             abc
 1002   2020-08-20 15:45:03  0.049398  true   false   0x3d4f4fbf    TestController             abc
Affect(row-cnt:3) cost in 3 ms.
  • -p: 该之类用于重做一次调用,一般来说,前端调起请求后。结果之前没看到,再次在前端调起太麻烦,那么可以使用该参数
tt -i 1000 -p

上述1000是指索引,重新请求类似于-i输出消息

[arthas@26932]$ tt -i 1000 -p
 RE-INDEX       1000
 GMT-REPLAY     2020-08-20 16:03:18
 OBJECT         0x3d4f4fbf
 CLASS          cn.appblog.arthas.TestController
 METHOD         abc
 PARAMETERS[0]  @Integer[20]
 IS-RETURN      true
 IS-EXCEPTION   false
 COST(ms)       0.200501
 RETURN-OBJ     @User[
                    name=@String[Joe.Ye],
                    age=@Integer[20],
                ]
Time fragment[1000] successfully replayed 1 times.
  • -n: 指定抓取次数,达到次数后自动停止
tt -t *TestController abc -n 3
[arthas@26932]$ tt -t *TestController abc -n 3
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 2
 INDEX  TIMESTAMP          COST(ms)  IS-RET  IS-EXP  OBJECT        CLASS                      METHOD
-----------------------------------------------------------------------------------------------------------------------
 1003   2020-08-20 16:05:48  0.0771    true   false   0x3d4f4fbf    TestController             abc
 1004   2020-08-20 16:05:48  0.0307    true   false   0x3d4f4fbf    TestController             abc
 1005   2020-08-20 16:05:49  0.026501  true   false   0x3d4f4fbf    TestController             abc
Command execution times exceed limit: 3, so command will exit. You can set it with -n option.
  • -w: 用作输出信息,可以找出请求过的信息,参数、以及是否抛出异常

找出正常返回对象、已经请求参数值

tt -i 1000 -w '{params[0], target, returnObj}'
[arthas@26932]$ tt -i 1000 -w '{params[0], target, returnObj}'
@ArrayList[
    @Integer[20],
    @TestController[cn.appblog.arthas.TestController@3d4f4fbf],
    @User[User(name=Joe.Ye, age=20)],
]
Affect(row-cnt:1) cost in 52 ms.

出现异常的线程,找出相关异常信息

tt -i 1001 -w '{params[0], target,throwExp}'
[arthas@26932]$ tt -i 1001 -w '{params[0], target,throwExp}'
@ArrayList[
    null,
    @TestController[cn.appblog.arthas.TestController@3d4f4fbf],
    @NullPointerException[java.lang.NullPointerException],
]
Affect(row-cnt:1) cost in 1 ms.

如果我们发现异常,想看看什么异常,怎么办呢?

tt -i 1001 -w throwExp
[arthas@26932]$ tt -i 1001 -w throwExp
java.lang.NullPointerException
        at cn.appblog.arthas.TestController.abc(TestController.java:16)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

Affect(row-cnt:1) cost in 1 ms.

dashboard

当前系统的实时数据面板,可以显示 JVM 内存使用情况,Java 版本信息

[arthas@26932]$ dashboard
ID        NAME                          GROUP               PRIORITY STATE     %CPU      TIME      INTERRUPT DAEMON
5         Attach Listener               system              5        RUNNABLE  0         0:0       false     true
20        Catalina-utility-1            main                1        WAITING   0         0:0       false     false
21        Catalina-utility-2            main                1        TIMED_WAI 0         0:0       false     false
38        DestroyJavaVM                 main                5        RUNNABLE  0         0:3       false     false
3         Finalizer                     system              8        WAITING   0         0:0       false     true
6         Monitor Ctrl-Break            main                5        RUNNABLE  0         0:0       false     true
16        RMI Scheduler(0)              system              5        WAITING   0         0:0       false     true
12        RMI TCP Accept-0              system              5        RUNNABLE  0         0:0       false     true
2         Reference Handler             system              10       WAITING   0         0:0       false     true
4         Signal Dispatcher             system              9        RUNNABLE  0         0:0       false     true
54        Timer-for-arthas-dashboard-49 system              5        RUNNABLE  0         0:0       false     true
46        arthas-NettyHttpTelnetBootstr system              5        RUNNABLE  0         0:0       false     true
52        arthas-NettyHttpTelnetBootstr system              5        RUNNABLE  0         0:0       false     true
Memory                    used    total    max     usage    GC
heap                      100M    247M     3614M   2.79%    gc.ps_scavenge.count          5
ps_eden_space             62M     64M      1325M   4.69%    gc.ps_scavenge.time(ms)       105
ps_survivor_space         10M     10M      10M     99.87%   gc.ps_marksweep.count         2
ps_old_gen                28M     172M     2711M   1.03%    gc.ps_marksweep.time(ms)      194
nonheap                   50M     56M      -1      89.09%
code_cache                3M      7M       240M    1.55%
Runtime
os.name                                                     Windows 10
os.version                                                  10.0
java.version                                                1.8.0_231
java.home                                                   C:\Program Files\Java\jdk1.8.0_231\jre
systemload.average                                          -1.00
processors                                                  4
uptime                                                      3527s

thread

常见参数

  • -i: 指定时间内采集
thread -i 2000

效果和thread类似,但是是一段时间数据

[arthas@26932]$ thread -i 2000
Threads Total: 32, NEW: 0, RUNNABLE: 12, BLOCKED: 0, WAITING: 16, TIMED_WAITING: 4, TERMINATED: 0
ID        NAME                          GROUP               PRIORITY STATE     %CPU      TIME      INTERRUPT DAEMON
5         Attach Listener               system              5        RUNNABLE  0         0:0       false     true
20        Catalina-utility-1            main                1        WAITING   0         0:0       false     false
21        Catalina-utility-2            main                1        TIMED_WAI 0         0:0       false     false
38        DestroyJavaVM                 main                5        RUNNABLE  0         0:3       false     false
3         Finalizer                     system              8        WAITING   0         0:0       false     true
6         Monitor Ctrl-Break            main                5        RUNNABLE  0         0:0       false     true
16        RMI Scheduler(0)              system              5        WAITING   0         0:0       false     true
12        RMI TCP Accept-0              system              5        RUNNABLE  0         0:0       false     true
2         Reference Handler             system              10       WAITING   0         0:0       false     true
4         Signal Dispatcher             system              9        RUNNABLE  0         0:0       false     true
46        arthas-NettyHttpTelnetBootstr system              5        RUNNABLE  0         0:0       false     true
52        arthas-NettyHttpTelnetBootstr system              5        RUNNABLE  0         0:0       false     true
47        arthas-NettyWebsocketTtyBoots system              5        RUNNABLE  0         0:0       false     true
50        arthas-UserStat               system              5        WAITING   0         0:0       false     true
53        arthas-command-execute        system              5        RUNNABLE  0         0:1       false     true
48        arthas-shell-server           system              5        TIMED_WAI 0         0:0       false     true
49        arthas-shell-server           system              5        TIMED_WAI 0         0:0       false     true
45        arthas-timer                  system              5        WAITING   0         0:0       false     true
22        container-0                   main                5        TIMED_WAI 0         0:0       false     false
36        http-nio-8080-Acceptor        main                5        RUNNABLE  0         0:0       false     true
24        http-nio-8080-BlockPoller     main                5        RUNNABLE  0         0:0       false     true
35        http-nio-8080-ClientPoller    main                5        RUNNABLE  0         0:0       false     true
25        http-nio-8080-exec-1          main                5        WAITING   0         0:0       false     true
34        http-nio-8080-exec-10         main                5        WAITING   0         0:0       false     true
26        http-nio-8080-exec-2          main                5        WAITING   0         0:0       false     true
27        http-nio-8080-exec-3          main                5        WAITING   0         0:0       false     true
28        http-nio-8080-exec-4          main                5        WAITING   0         0:0       false     true
  • -n: 找出 cpu 使用率最高的几个线程
thread -n 3
[arthas@26932]$ thread -n 3
"Reference Handler" Id=2 cpuUsage=0% WAITING on java.lang.ref.Reference$Lock@94829b
    at java.lang.Object.wait(Native Method)
    -  waiting on java.lang.ref.Reference$Lock@94829b
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"Finalizer" Id=3 cpuUsage=0% WAITING on java.lang.ref.ReferenceQueue$Lock@63956277
    at java.lang.Object.wait(Native Method)
    -  waiting on java.lang.ref.ReferenceQueue$Lock@63956277
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Signal Dispatcher" Id=4 cpuUsage=0% RUNNABLE
  • -b

找到持有锁的线程,有时候请求后,一直卡住,那么可以使用该方式去查找持有锁的线程。注意该方式不支持显示锁也就是lock接口的

thread -b
[arthas@26932]$ thread -b
No most blocking thread found!

jvm

输出 jvm 相关信息,包括加载类的路径,启动类路径,加载类个数等等

trace 命令

该命令有点强,用于查看接口调用时间,可以找出接口在调用不同方法时所花费的时间,可以用作性能调优。

常用参数:

  • -n: 有时候请求量太大,我们不需要每个请求调用时间,那么可以使用这个参数,指定次数调用后结束。
trace *TestController abc -n 2
[arthas@26932]$ trace *TestController abc -n 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 66 ms, listenerId: 3
`---ts=2020-08-20 16:29:51;thread_name=http-nio-8080-exec-6;id=1e;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@4f936da8
    `---[0.2568ms] cn.appblog.arthas.TestController:abc()
        +---[0.0362ms] cn.appblog.arthas.User:<init>() #19
        +---[0.018ms] cn.appblog.arthas.User:setName() #20
        `---[0.018599ms] cn.appblog.arthas.User:setAge() #21

`---ts=2020-08-20 16:30:04;thread_name=http-nio-8080-exec-7;id=1f;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@4f936da8
    `---[0.394099ms] cn.appblog.arthas.TestController:abc()
        +---[0.0449ms] cn.appblog.arthas.User:<init>() #19
        +---[0.0302ms] cn.appblog.arthas.User:setName() #20
        `---[0.0576ms] cn.appblog.arthas.User:setAge() #21

Command execution times exceed limit: 2, so command will exit. You can set it with -n option.

我们也可以进行筛选,比如我们要找出请求时间大于 10ms 的线程,如下命令即可。

trace *TestController abc '#cost>10'

watch 命令

常用参数:

  • -b: 在调用方法前观察这个方法,可以看到传入的参数值
watch -b *TestController abc params
[arthas@26932]$ watch -b *TestController abc params
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 4
ts=2020-08-20 16:33:04; [cost=0.062801ms] result=@Object[][
    @Integer[22],
]
ts=2020-08-20 16:33:10; [cost=0.023ms] result=@Object[][
    @Integer[25],
]
  • -e: 观察抛出异常时传入参数
watch -e *TestController abc params
[arthas@26932]$ watch -e *TestController abc params
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 5
ts=2020-08-20 16:34:22; [cost=0.200399ms] result=@Object[][
    @Integer[0],
]
ts=2020-08-20 16:34:43; [cost=0.880799ms] result=@Object[][
    null,
]
  • -f: 方法调用完成,返回对象是观察具体数据
watch -f *TestController abc params
[arthas@26932]$ watch -f *TestController abc params
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 38 ms, listenerId: 6
ts=2020-08-20 16:36:37; [cost=0.0628ms] result=@Object[][
    @Integer[22],
]
ts=2020-08-20 16:36:55; [cost=0.6637ms] result=@Object[][
    @Integer[0],
]

假设我们想观察详细一些怎么做呢?
先看看我们抛出异常的情况,只是看异常,不看具体堆栈

watch *TestController abc '{params,target,throwExp}'
[arthas@26932]$ watch *TestController abc '{params,target,throwExp}'
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 29 ms, listenerId: 7
ts=2020-08-20 16:38:29; [cost=0.278899ms] result=@ArrayList[
    @Object[][isEmpty=false;size=1],
    @TestController[cn.appblog.arthas.TestController@3d4f4fbf],
    @NullPointerException[java.lang.NullPointerException],
]

查看具体堆栈的在后面加-x 2,意思是输出2层的结果,默认情况下我们只输出异常(也是就默认-x 1

watch *TestController abc '{params,target,throwExp}' -x 2
[arthas@26932]$ watch *TestController abc '{params,target,throwExp}' -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 26 ms, listenerId: 8
ts=2020-08-20 16:40:11; [cost=0.1639ms] result=@ArrayList[
    @Object[][
        null,
    ],
    @TestController[
    ],
    java.lang.NullPointerException
        at cn.appblog.arthas.TestController.abc(TestController.java:16)
        at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
,
]

可以尝试多种情况,比如将所有参数,返回结果都输出

watch *TestController abc '{params,target,returnObj}' -x 2
[arthas@26932]$ watch *TestController abc '{params,target,returnObj}' -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 27 ms, listenerId: 9
ts=2020-08-20 16:41:37; [cost=0.0707ms] result=@ArrayList[
    @Object[][
        @Integer[22],
    ],
    @TestController[
    ],
    @User[
        name=@String[Joe.Ye],
        age=@Integer[22],
    ],
]

stack 命令

该命令霸道,看源码执行方式必备呀。比如:我们看到一个核心方法,但是发现这个方法会被执行的路径很多,我们很难找到到底哪个执行了,那这个命令就体现其强大之处了。

常用命令:

  • -n: 指定结束次数,达到次数则自动退出,不继续监听
stack *User setName -n 1

上面那个命令,用我们一个User类的setName方法来查看,发现就是我们TestController调用了。

[arthas@26932]$ stack *User setName -n 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 27 ms, listenerId: 10
ts=2020-08-20 16:44:07;thread_name=http-nio-8080-exec-2;id=1a;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@4f936da8
    @cn.appblog.arthas.User.setName()
        at cn.appblog.arthas.TestController.abc(TestController.java:20)
        at sun.reflect.GeneratedMethodAccessor20.invoke(null:-1)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

Command execution times exceed limit: 1, so command will exit. You can set it with -n option.

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/25/arthas-alibaba-online-diagnostic-artifact/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Arthas(阿尔萨斯) — 阿里在线诊断神器
Arthas简介 Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。 Arthas 支持JDK 6+,支持Li……
<<上一篇
下一篇>>
文章目录
关闭
目 录