ToB企服应用市场:ToB评测及商务社交产业平台

标题: 一文吃透Arthas常用命令! [打印本页]

作者: 八卦阵    时间: 2023-4-11 08:59
标题: 一文吃透Arthas常用命令!
Arthas 常用命令

简介

Arthas 是Alibaba开源的Java诊断工具,动态跟踪Java代码;实时监控JVM状态,可以在不中断程序执行的情况下轻松完成JVM相关问题排查工作 。支持JDK 6+,支持Linux/Mac/Windows。这个工具真的很好用,而且入门超简单,十分推荐。
使用场景

本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~
Github地址
如果访问不了Github,可以访问gitee地址。
gitee地址
安装

执行下面命令下载
  1. wget https://alibaba.github.io/arthas/arthas-boot.jar
复制代码
用java -jar的方式启动
  1. java -jar arthas-boot.jar
  2. [INFO] Found existing java process, please choose one and hit RETURN.
  3. * [1]: 79952 cn.test.MobileApplication
  4.   [2]: 93872 org.jetbrains.jps.cmdline.Launcher
复制代码
然后输入数字,选择你想要监听的应用,回车即可
常用命令

查询arthas版本
  1. [arthas@79952]$ version
  2. 3.1.4
复制代码
1、stack

输出当前方法被调用的调用路径
很多时候我们都知道一个方法被执行,但是有很多地方调用了它,你并不知道是谁调用了它,此时你需要的是 stack 命令。
参数名称参数说明class-pattern类名表达式匹配method-pattern方法名表达式匹配
  1. [arthas@79952]$ stack com.baomidou.mybatisplus.extension.service.IService getOne
  2. Press Q or Ctrl+C to abort.
  3. Affect(class-cnt:202 , method-cnt:209) cost in 10761 ms.
  4. ts=2019-11-13 11:49:13;thread_name=http-nio-8801-exec-6;id=2d;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@a6c54c3
  5.     @com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne()
  6.         at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:230)
  7.         ...... ......
  8.         at cn.test.mobile.controller.order.OrderController.getOrderInfo(OrderController.java:500)
复制代码
可以看到OrderController.java的第500行调用了这个getOne接口。
注意这个命令需要调用后才会触发日志,相似的还有watch、trace等
最全面的Java面试网站
2、jad

反编译指定已加载类的源码
有时候,版本发布后,代码竟然没有执行,代码是最新的吗,这时可以使用jad反编译相应的class。
  1. jad cn.test.mobile.controller.order.OrderController
复制代码
仅编译指定的方法
  1. jad cn.test.mobile.controller.order.OrderController getOrderInfo
  2. ClassLoader:
  3. @RequestMapping(value={"getOrderInfo"}, method={RequestMethod.POST})
  4. public Object getOrderInfo(HttpServletRequest request, @RequestBody Map map) {
  5.     ResponseVo responseVo = new ResponseVo();
  6.     ... ... ...  ...
复制代码
3、sc

“Search-Class” 的简写 ,查看JVM已加载的类信息 有的时候,你只记得类的部分关键词,你可以用sc获取完整名称 当你碰到这个错的时候“ClassNotFoundException”或者“ClassDefNotFoundException”,你可以用这个命令验证下
参数名称参数说明class-pattern类名表达式匹配method-pattern方法名表达式匹配[d]输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。如果一个类被多个ClassLoader所加载,则会出现多次模糊搜索
  1. sc *OrderController*
  2. cn.test.mobile.controller.order.OrderController
复制代码
打印类的详细信息  sc -d
  1. sc -d cn.test.mobile.controller.order.OrderController
  2. class-info        cn.test.mobile.controller.order.OrderController
  3. code-source       /F:/IDEA-WORKSPACE-TEST-qyb/trunk/BE/mobile/target/classes/
  4. name              cn.test.mobile.controller.order.OrderController
  5. isInterface       false
  6. isAnnotation      false
  7. isEnum            false
  8. isAnonymousClass  false
  9. isArray           false
  10. isLocalClass      false
  11. isMemberClass     false
  12. isPrimitive       false
  13. isSynthetic       false
  14. simple-name       OrderController
  15. modifier          public
  16. annotation        org.springframework.web.bind.annotation.RestController,org.springframework.web.bind.annotation.Requ
  17.                    estMapping
  18. interfaces
  19. super-class       +-cn.test.mobile.controller.BaseController
  20.                      +-java.lang.Object
  21. class-loader      +-sun.misc.Launcher$AppClassLoader@18b4aac2
  22.                      +-sun.misc.Launcher$ExtClassLoader@480bdb19
  23. classLoaderHash   18b4aac2
复制代码
与之相应的还有sm( “Search-Method”  ),查看已加载类的方法信息
查看String里的方法
  1. sm java.lang.String
  2. java.lang.String <init>([BII)V
  3. java.lang.String <init>([BLjava/nio/charset/Charset;)V
  4. java.lang.String <init>([BLjava/lang/String;)V
  5. java.lang.String <init>([BIILjava/nio/charset/Charset;)V
  6. java.lang.String <init>([BIILjava/lang/String;)V
  7. ... ... ... ...
复制代码
查看String中toString的详细信息
  1. sm -d java.lang.String toString
  2. declaring-class  java.lang.String
  3. method-name      toString
  4. modifier         public
  5. annotation
  6. parameters
  7. return           java.lang.String
  8. exceptions
  9. classLoaderHash  null
复制代码
4、watch

可以监测一个方法的入参和返回值
有些问题线上会出现,本地重现不了,这时这个命令就有用了
参数名称参数说明class-pattern类名表达式匹配method-pattern方法名表达式匹配express观察表达式condition-express条件表达式方法调用之前观察[e]在方法异常之后观察方法返回之后观察[f]在方法结束之后(正常返回和异常返回)观察,默认选项[E]开启正则表达式匹配,默认为通配符匹配[x:]指定输出结果的属性遍历深度,默认为 1观察getOrderInfo的出参和返回值,出参就是方法结束后的入参
  1. watch cn.test.mobile.controller.order.OrderController getOrderInfo "{params,returnObj}" -x 2
  2. Press Q or Ctrl+C to abort.
  3. Affect(class-cnt:1 , method-cnt:1) cost in 456 ms.
  4. ts=2019-11-13 15:30:18; [cost=18.48307ms] result=@ArrayList[
  5.     @Object[][  # 这个就是出参,params
  6.         @RequestFacade[org.apache.catalina.connector.RequestFacade@1d81dbd7],
  7.         @LinkedHashMap[isEmpty=false;size=2], # 把遍历深度x改为3就可以查看map里的值了
  8.     ],
  9.     @ResponseVo[ # 这个就是返回值 returnObj
  10.         log=@Logger[Logger[cn.test.db.common.vo.ResponseVo]],
  11.         success=@Boolean[true],
  12.         message=@String[Ok],
  13.         count=@Integer[0],
  14.         code=@Integer[1000],
  15.         data=@HashMap[isEmpty=false;size=1],
  16.     ],
  17. ]
复制代码
观察getOrderInfo的入参和返回值
  1. watch cn.test.mobile.controller.order.OrderController getOrderInfo "{params,returnObj}" -x 3 -b
  2. Press Q or Ctrl+C to abort.
  3. Affect(class-cnt:1 , method-cnt:1) cost in 93 ms.
  4. ts=2019-11-13 15:37:38; [cost=0.012479ms] result=@ArrayList[
  5.     @Object[][
  6.         @RequestFacade[
  7.             request=@Request[org.apache.catalina.connector.Request@d04e652],
  8.             sm=@StringManager[org.apache.tomcat.util.res.StringManager@7ae7a97b],
  9.         ],
  10.         @LinkedHashMap[
  11.             @String[payNo]:@String[190911173713755288],
  12.             @String[catalogId]:@String[6],
  13.         ],
  14.     ],
  15.     null,# -b是方法调用之前观察,所以还没有返回值
  16. ]
复制代码
如果需要捕捉异常的话,使用throwExp,如{params,returnObj,throwExp}
5、trace

输出方法内部调用路径,和路径上每个节点的耗时
可以通过这个命令,查看哪些方法耗性能,从而找出导致性能缺陷的代码,这个耗时还包含了arthas执行的时间哦。
参数名称参数说明class-pattern类名表达式匹配method-pattern方法名表达式匹配condition-express条件表达式[E]开启正则表达式匹配,默认为通配符匹配[n:]命令执行次数#cost方法执行耗时输出getOrderInfo的调用路径
  1. trace -j cn.test.mobile.controller.order.OrderController getOrderInfo
  2. Press Q or Ctrl+C to abort.
  3. Affect(class-cnt:1 , method-cnt:1) cost in 92 ms.
  4. ---ts=2019-11-13 15:46:59;thread_name=http-nio-8801-exec-4;id=2b;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@a6c54c3
  5.     ---[15.509011ms] cn.test.mobile.controller.order.OrderController:getOrderInfo()
  6.         +---[0.03584ms] cn.test.db.common.vo.ResponseVo:<init>() #472
  7.         +---[0.00992ms] java.util.HashMap:<init>() #473
  8.         +---[0.02176ms] cn.test.mobile.controller.order.OrderController:getUserInfo() #478
  9.         +---[0.024ms] java.util.Map:get() #483
  10.         +---[0.00896ms] java.lang.Object:toString() #483
  11.         +---[0.00864ms] java.lang.Integer:parseInt() #483
  12.         +---[0.019199ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:<init>() #500
  13.         +---[0.135679ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:allEq() #500
  14.         +---[12.476072ms] cn.test.db.service.IOrderMediaService:getOne() #500
  15.         +---[0.0128ms] java.util.HashMap:put() #501
  16.         +---[0.443517ms] cn.test.db.common.vo.ResponseVo:setSuccess() #503
  17.         `---[0.03488ms] java.util.Map:put() #504
复制代码
输出getOrderInfo的调用路径,且cost大于10ms,-j是指过滤掉jdk中的方法,可以看到输出少了很多
  1. trace -j cn.test.mobile.controller.order.OrderController getOrderInfo '#cost > 10'
  2. Press Q or Ctrl+C to abort.
  3. Affect(class-cnt:1 , method-cnt:1) cost in 96 ms.
  4. ---ts=2019-11-13 15:53:42;thread_name=http-nio-8801-exec-2;id=29;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@a6c54c3
  5.     ---[13.803743ms] cn.test.mobile.controller.order.OrderController:getOrderInfo()
  6.         +---[0.01312ms] cn.test.db.common.vo.ResponseVo:<init>() #472
  7.         +---[0.01408ms] cn.test.mobile.controller.order.OrderController:getUserInfo() #478
  8.         +---[0.0128ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:<init>() #500
  9.         +---[0.303998ms] com.baomidou.mybatisplus.core.conditions.query.QueryWrapper:allEq() #500
  10.         +---[12.675431ms] cn.test.db.service.IOrderMediaService:getOne() #500
  11.         `---[0.409917ms] cn.test.db.common.vo.ResponseVo:setSuccess() #503
复制代码
6、jobs

执行后台异步任务
线上有些问题是偶然发生的,这时就需要使用异步任务,把信息写入文件。
使用 & 指定命令去后台运行,使用 > 将结果重写到日志文件,以trace为例
  1. trace -j cn.test.mobile.controller.order.OrderController getOrderInfo > test.out &
复制代码
jobs——列出所有job
  1. jobs
  2. [76]*  
  3.        Running           trace -j cn.test.mobile.controller.order.OrderController getOrderInfo >> test.out &
  4.        execution count : 0
  5.        start time      : Wed Nov 13 16:13:23 CST 2019
  6.        timeout date    : Thu Nov 14 16:13:23 CST 2019
  7.        session         : f4fba846-e90b-4234-959e-e78ad0a5db8c (current)
复制代码
job id是76, * 表示此job是当前session创建,状态是Running,execution count是执行次数,timeout date是超时时间
异步执行时间,默认为1天,如果要修改,使用options命令,
  1. options job-timeout 2d
复制代码
options可选参数 1d, 2h, 3m, 25s,分别代表天、小时、分、秒
kill——强制终止任务
  1. kill 76
  2. kill job 76 success
复制代码
最多同时支持8个命令使用重定向将结果写日志
请勿同时开启过多的后台异步命令,以免对目标JVM性能造成影响
7、logger

查看logger信息,更新logger level
查看
  1. logger
  2. name                ROOT
  3. class               ch.qos.logback.classic.Logger
  4. classLoader         sun.misc.Launcher$AppClassLoader@18b4aac2
  5. classLoaderHash     18b4aac2 #改日志级别时要用到它
  6. level               INFO
  7. effectiveLevel      INFO
  8. ... ... ... ...
复制代码
更新日志级别
  1. logger --name ROOT --level debug
  2. update logger level success.
复制代码
如果执行这个命令时出错:update logger level fail.
指定classLoaderHash重试一下试试
  1. logger -c 18b4aac2 --name ROOT --level debug
  2. update logger level success.
复制代码
8、dashboard

查看当前系统的实时数据面板 这个命令可以全局的查看jvm运行状态,比如内存和cpu占用情况
  1. dashboard
  2. ID        NAME                          GROUP               PRIORITY STATE     %CPU      TIME      INTERRUPT DAEMON
  3. 17        Abandoned connection cleanup  main                5        TIMED_WAI 0         0:0       false     true
  4. 1009      AsyncAppender-Worker-arthas-c system              5        WAITING   0         0:0       false     true
  5. 5         Attach Listener               system              5        RUNNABLE  0         0:0       false     true
  6. 23        ContainerBackgroundProcessor[ main                5        TIMED_WAI 0         0:0       false     true
  7. 55        DestroyJavaVM                 main                5        RUNNABLE  0         0:11      false     false
  8. 3         Finalizer                     system              8        WAITING   0         0:0       false     true
  9. 18        HikariPool-1 housekeeper      main                5        TIMED_WAI 0         0:0       false     true
  10. 39        NioBlockingSelector.BlockPoll main                5        RUNNABLE  0         0:0       false     true
  11. 2         Reference Handler             system              10       WAITING   0         0:0       false     true
  12. 4         Signal Dispatcher             system              9        RUNNABLE  0         0:0       false     true
  13. 69        System Clock                  main                5        TIMED_WAI 0         0:34      false     true
  14. 25        Thread-2                      main                5        TIMED_WAI 0         0:0       false     false
  15. 37        Timer-0                       main                5        TIMED_WAI 0         0:0       false     true
  16. Memory                    used    total    max     usage    GC
  17. heap                      216M    415M     3614M   5.99%    gc.ps_scavenge.count          96
  18. ps_eden_space             36M     78M      1276M   2.90%    gc.ps_scavenge.time(ms)       3054
  19. ps_survivor_space         17M     38M      38M     46.53%   gc.ps_marksweep.count         4
  20. ps_old_gen                161M    298M     2711M   5.97%    gc.ps_marksweep.time(ms)      804
  21. nonheap                   175M    180M     -1      97.09%
  22. code_cache                35M     35M      240M    14.85%
复制代码
ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应 我们可以通过 thread id 查看线程的堆栈 信息
  1. thread 2
  2. "Reference Handler" Id=2 WAITING on java.lang.ref.Reference$Lock@66ad4272
  3.     at java.lang.Object.wait(Native Method)
  4.     -  waiting on java.lang.ref.Reference$Lock@66ad4272
  5.     at java.lang.Object.wait(Object.java:502)
  6.     at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
  7.     at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
复制代码
NAME: 线程名
GROUP: 线程组名
PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
STATE: 线程的状态
CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
TIME: 线程运行总时间,数据格式为分:秒
INTERRUPTED: 线程当前的中断位状态
DAEMON: 是否是daemon线程
9、redefine

redefine jvm已加载的类 ,可以在不重启项目的情况下,热更新类。
这个功能真的很强大,但是命令不一定会成功
下面我们来模拟:假设我想修改OrderController里的某几行代码,然后热更新至jvm:
a. 反编译OrderController,默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用
  1. jad --source-only cn.test.mobile.controller.order.OrderController > OrderController.java
复制代码
生成的OrderController.java在哪呢,执行pwd就知道在哪个目录了
b. 查找加载OrderController的ClassLoader
  1. sc -d cn.test.mobile.controller.order.OrderController | grep classLoaderHash
  2. classLoaderHash   18b4aac2
复制代码
c. 修改保存好OrderController.java之后,使用mc(Memory Compiler)命令来编译成字节码,并且通过-c参数指定ClassLoader
  1. mc -c 18b4aac2 OrderController.java -d ./
复制代码
d. 热更新刚才修改后的代码
  1. redefine -c 18b4aac2 OrderController.class
  2. redefine success, size: 1
复制代码
然后代码就更新成功了。
其他

如果java -jar选择启动某个应用的时候,报下面的错
  1. java -jar arthas-boot.jar
  2. [INFO] arthas-boot version: 3.1.4
  3. [INFO] Process 11544 already using port 3658
  4. [INFO] Process 11544 already using port 8563
  5. [INFO] Found existing java process, please choose one and hit RETURN.
  6. * [1]: 11544
  7.   [2]: 119504 cn.test.MobileApplication
  8.   [3]: 136340 org.jetbrains.jps.cmdline.Launcher
  9.   [4]: 3068
  10. 2 #选择第2个启动
  11. [ERROR] Target process 119504 is not the process using port 3658, you will connect to an unexpected process.
  12. [ERROR] 1. Try to restart arthas-boot, select process 11544, shutdown it first with running the 'shutdown' command.
  13. [ERROR] 2. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
复制代码
注意提示[ERROR] 1,只需要进入11544这个应用,然后执行shutdown关闭这个应用就可以启动了
最后给大家分享一个Github仓库,上面有大彬整理的300多本经典的计算机书籍PDF,包括C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,可以star一下,下次找书直接在上面搜索,仓库持续更新中~


Github地址

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4