• Arthas 使用(一) —— 基础命令




    Arthas 简介

    Arthas 是 Alibaba 开源的 Java 诊断工具,根据官方介绍,它提供了如下工功能:

    image-20200517111854420

    官方文档地址: https://alibaba.github.io/arthas/

    github 源码地址: https://github.com/alibaba/arthas


    Arthas 安装

    启动 Arthas

    # 下载 arthas
    curl -O https://alibaba.github.io/arthas/arthas-boot.jar
    # 通过如下命令启动
    java -jar arthas-boot.jar
    

    image-20200517155128106

    选择进程 id 按下回车,就可以连接到对应的 java 应用,首次启动会下载一些文件到 "C:/Users/${user}/.arthas/lib/3.2.0/arthas" 目录

    20200517154635722

    arthas 启动支持多个参数,可以使用 -h 查看

    image-20200517161835635

    EXAMPLES:
      java -jar arthas-boot.jar <pid>
      java -jar arthas-boot.jar --target-ip 0.0.0.0
      java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
      java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
      java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
    --agent-id bvDOe8XbTM2pQWjF4cfw
      java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'
      java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
      java -jar arthas-boot.jar -f batch.as <pid>
      java -jar arthas-boot.jar --use-version 3.2.0
      java -jar arthas-boot.jar --versions
      java -jar arthas-boot.jar --session-timeout 3600
      java -jar arthas-boot.jar --attach-only
      java -jar arthas-boot.jar --repo-mirror aliyun --use-http
    WIKI:
      https://alibaba.github.io/arthas
    

    help

    arthas 连接成功后,使用 help 可以看到提供的一些命令

    image-20200517155940521

    每个命令可以使用 -h 参数查看帮助信息,里面有EXAMPLESWIKI链接

    image-20200517154635722


    webconsole

    arthas 启动后,可以通过浏览器进行访问,地址 http://localhost:8563/

    image-20200517162105397


    退出

    如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。

    如果想完全退出arthas,可以执行stop命令。


    Arthas 命令

    dashboard

    查看面板信息,主要包含cpu 内存使用信息,可以按 Ctrl+C 或者 输入 q 退出

    _images/dashboard.png

    数据说明

    • ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
    • NAME: 线程名
    • GROUP: 线程组名
    • PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
    • STATE: 线程的状态
    • CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
    • TIME: 线程运行总时间,数据格式为分:秒
    • INTERRUPTED: 线程当前的中断位状态
    • DAEMON: 是否是daemon线程

    thread

    查看线程使用情况

    # 查看所有线程信息
    thread
    # 查看具体线程的栈,查看线程ID 16的栈:
    thread 16
    # 查看CPU使用率top n线程的栈
    thread -n 3
    # 查看5秒内的CPU使用率top n线程栈
    thread -n 3 -i 5000
    # 查找线程是否有阻塞
    thread -b
    

    image-20200517163025955


    sysprop

    查看当前JVM的系统属性,支持 pipeline

    sysprop # 查询所有属性
    sysprop key # 查看key对应的属性
    sysprop key value # 修改属性值
    sysprop | grep java # 查询包含java的属性
    sysprop | wc -l # 统计数量
    

    image-20200517163647024


    sysenv

    查看当前JVM的环境属性

    用法和 sysprop 类似,不支持修改

    image-20200517170505831


    logger

    查看logger信息,更新logger level

    logger # 查看所有logger对象信息
    logger -n [name] # 查看名为name的logger信息
    logger -c [classloader] -n [name] -l ERROR # 修改名为name的logger级别为ERROR,需指定类加载器
    

    image-20200517165827604


    sc

    查看JVM已加载的类信息

    sc -d org.apache.commons.lang.StringUtils # 查看StringUtils详细信息
    sc -d org/apache/commons/lang/StringUtils # 查看StringUtils详细信息
    sc -d *StringUtils # 查看StringUtils,根据*匹配
    sc -d -f org.apache.commons.lang.StringUtils # 查看类及成员变量信息,f要配合d使用才有效
    

    image-20200517165504773


    sm

    查看已加载类的方法信息,用法和 sc 类似

    sm java.lang.String # 查看String的所有方法
    sm -d org.apache.commons.lang.StringUtils # 查看String方法详情
    sm -d org/apache/commons/lang/StringUtils # 查看String方法详情
    sm *StringUtils *  # 查看String方法,根据*匹配
    

    image-20200517170620766


    dump

    dump 已加载类的 bytecode 到特定目录

    dump java.lang.String # dump java.lang.String.class文件
    dump java.lang.* # dump 批量dump
    dump -d /tmp/output java.lang.String # dump到指定目录
    dump org/apache/commons/lang/StringUtils # dump,支持目录格式
    dump *StringUtils # dump,根据*匹配
    

    image-20200517164153476


    jad

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

    jad java.lang.String # 反编译String类
    jad java.lang.String toString # 反编译指定方法
    jad --source-only java.lang.String # 反编绎时只显示源代码
    jad -c 39eb305e org/apache/log4j/Logger # 反编译指定classloader
    

    image-20200517171304855


    classloader

    查看classloader的继承树,urls,类加载信息

    classloader	# 列出所有classLoader
    classloader -t # 树形结构列出所有classLoader
    classloader -l # 统计每个classLoader加载类数量
    classloader -c 327a647b # 查看具体的classLoader
    classloader -a # 列出所有加载的类
    classloader -c 659e0bfd --load demo.MathGame # 使用指定classLoader加载类
    

    image-20200517171909021


    mc

    编译.java文件生成.class

    mc /tmp/Test.java	# 编译Test.java
    mc -c 327a647b /tmp/Test.java # 使用 -c 指定classLoader
    mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java # 使用 -d 指定输出目录
    

    redefine

    加载外部的.class文件

    redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。 原因是jdk本身redefine和Retransform是不同的机制,同时使用两种机制来更新字节码,只有最后修改的会生效。

    redefine /tmp/Test.class	# 加载类
    redefine -c 327a647b /tmp/Test.class /tmp/Test$Inner.class # 指定classLoader
    

    通常结合 jad/mc 使用

    • jad命令反编译,然后可以用其它编译器,比如vim来修改源码
    • mc命令来内存编译修改过的代码
    • 用redefine命令加载新的字节码

    redefine的限制

    • 不允许新增加 field/method
    • 正在跑的函数,没有退出不能生效

    watch

    方法执行数据观测

    # 方法调用前观察,可以是非静态方法
    watch -b org.apache.commons.lang.StringUtils isBlank params
    # 在方法结束之后(正常返回和异常返回)观察
    watch -f org.apache.commons.lang.StringUtils isBlank returnObj
    # 指定输出结果的属性遍历深度,2
    watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj}' -x 2
    # 耗时100ms时输出
    watch *StringUtils isBlank params '#cost>100'
    
    @RestController
    public class UserController {
        @GetMapping("/user/{id}")
        public User getUser(@PathVariable Integer id) {
            if (null == id) {
                throw new IllegalArgumentException("id can not be null");
            }
            if (id < 1) {
                throw new IllegalArgumentException("id must be greater than 1");
            }
            return new User(id, "zhangsan");
        }
    }
    

    使用如下 watch 命令,然后访问 http://localhost:9090/user/10

    watch com.soulballad.usage.arthasdemo.web.UserController getUser "{params,target,returnObj}" -x 2 -b -s -n 2
    

    image-20200517175917004

    • 参数里-n 2,表示只执行两次
    • 输出结果中,第一次输出的是方法调用前的观察结果,第二次输出的是方法返回后的表达式的结果
    • 结果的输出顺序和事件发生的先后顺序一致,和命令中 -s -b 的顺序无关

    trace

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

    trace org.apache.commons.lang.StringUtils isBlank # 查看isBlank方法调用路径及耗时
    trace *StringUtils isBlank # 使用*匹配
    trace *StringUtils isBlank '#cost>100' # 过滤只输出耗时大于100ms的记录
    # 正则表达式,支持多个路径记录
    trace -E com.test.ClassA|org.test.ClassB method1|method2|method3 
    trace demo.MathGame run -n 5 # 只执行5次
    trace demo.MathGame run --skipJDKMethod false # 不跳过jdk中方法,默认为true
    

    image-20200517180614199


    stack

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

    image-20200517181157825

    支持条件过滤和 ognl 表达式


    tt

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

    tt -t *StringUtils isEmpty # 记录isEmpty方法调用
    tt -t *StringUtils isEmpty params[0].length==1 # 解决方法重载
    tt -l # 查看所有记录
    tt -i 1000 # 查询index为1000的记录详情
    tt -i 1000 -p # 根据index重新触发调用
    tt -i 1000 -p --replay-times 3 --replay-interval 3000 # 指定触发间隔和次数
    tt --delete-all # 删除所有记录
    

    image-20200517190220743


    ognl

    执行ognl表达式

    ognl '@java.lang.System@out.println("hello")' # 调用静态函数
    ognl -x 2 '@Singleton@getInstance()' # 2层
    ognl '@Demo@staticFiled' # 输出静态变量值
    # 把java.home和java.runtime.name的系统属性放到一个集合中输出
    ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
    ognl -c 5d113a51 '@com.taobao.arthas.core.GlobalOptions@isDump' # 输出false
    
  • 相关阅读:
    数组
    原生获取 键盘 keycode 鼠标 键码
    javascript 拖拽
    简单的鼠标拖拽
    vue中格式化时间戳
    使用koa+angular+mysql 完成了一个企业站
    koa2+mysql5+angularjs1 搭建前后端全栈项目
    javascript利用闭包实现迭代器轮询数组中的元素
    AngularJS 1.x版本 学习教程
    改变,从羡慕别人开始
  • 原文地址:https://www.cnblogs.com/col-smile/p/12906517.html
Copyright © 2020-2023  润新知