阿尔萨斯

发表信息: by

阿尔萨斯

从圣骑士到巫妖王

这里阿尔萨斯的故事

冰封王座的主角, 封面上的人物:

Alt text

阿里 Arthas

Alibaba开源的Java诊断工具, 以命令行的方式监控跟踪线上程序运行过程,解决一些棘手的问题。

这里Arthas的官方文档, 本文简单记录一些常用的手段。

安装

  • wget https://alibaba.github.io/arthas/arthas-boot.jar
    • 备用链接 wget https://arthas.gitee.io/arthas-boot.jar
  • java -jar arthas-boot.jar
    • 备用运行姿势 java -jar arthas-boot.jar --repo-mirror aliyun --use-http

命令

基本命令

help

查看帮助 Alt text

cls

清屏

session

当前会话

reset

重置增强类, shutdown的时候也会被reset

shutdown

关闭服务端

quit

关闭当前客户端

history

历史命令

version

版本

keymap

自定义快捷键

JVM相关命令

dashboard

Alt text

thread

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

doc

  • thread 查看所有线程概览
  • thread id 查看id线程的堆栈
    • thread 1
  • thread -n value 打印最忙的前value个线程的堆栈
    • thread -n 3
  • thread -b 打印阻塞其他线程的那个线程
  • thread -i value 打印统计value ms 后的cpu占比
    • thread -i 1000

jvm

查看jvm的信息

doc

sysprop

查看和修改当前JVM的系统属性

doc

sysenv

查看jvm的环境变量

doc

getstatic

查看静态变量

doc

  • getstatic class绝对路径 静态变量
  • getstatic class绝对路径 静态变量 'OGNL表达式'

Alt text

ognl

执行ognl 表达式

doc

  • ognl 'express' [-c classLoadHashCode] [-x value]
    • -c 执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader
    • -x 结果对象的展开层次,默认值1

class/class loader 相关命令

sc

查看JVM已加载的类信息

doc

  • sc class-partten [method-partten] [-d] [-E] [-f] [-x value]
    • -d 详细信息
    • -f 当前类的成员变量
    • -E 开启正则(默认通配符)

sm

查看JVM已加载的方法信息

doc

  • sm class-pattern [method-pattern] [-d] [-E]
    • -d 详细
    • -E 开启正则

Alt text

jad

反编译已加载的指定类

doc

  • jad class-pattern [method-pattern] [-c classLoadHashCode] [-E] [–source-only]

mc

内存编译

doc

  • mc xxx.java [-d value]
    • -d 生成class输出到 value

redifine

替换已经加载的class文件

doc

monitor/watch/trace相关

monitor

方法监控

doc

  • monitor class-patterm method-pattern [-c value] [-E]
    • -c 统计周期为value
    • -E 开启正则表达式

watch

方法执行数据监控

doc

  • watch class-pattern method-pattern 'express' ['condition-express'] [-b] [-e] [-s] [-f] [-E] [-x value] [-n value]
    • -b 在方法调用之前观察
    • -e 在方法异常之后观察
    • -s 在方法返回之后观察
    • -f 在方法结束之后观察
    • -x 对输出结果的遍历深度
    • -n 输出几次之后自动结束

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

下面是核心变量

public class Advice {
 
    private final ClassLoader loader;
    private final Class<?> clazz;
    private final ArthasMethod method;
    private final Object target;
    private final Object[] params;
    private final Object returnObj;
    private final Throwable throwExp;
    private final boolean isBefore;
    private final boolean isThrow;
    private final boolean isReturn;
    
    // getter/setter  
}  

trace

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

doc

  • trace class-pattern method-pattern ['condition-express'] [-E] [-n value]

stack

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

doc

  • stack class-pattern method-pattern ['condition-express'] [-E] [-n value]

tt

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

doc

ONGL

OGNL 是 Object-Graph Navigation Language 的缩写,从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置 java 对象的属性 , 它旨在提供一个更高抽象度语法来对 java 对象图进行导航

package ongltest;

import ognl.Ognl;
import ognl.OgnlException;

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws OgnlException {
        Student student = TotalFactory.genStudent1();

        Map<String, Object> map = new HashMap<>();
        map.put("student1", student);
        /**
         * <pre>
         * 1.ognl 缺省的上下文只有root和context
         * 2.#root 来显示的指定使用root还是使用context
         *
         * </pre>
         */
        // 获取student的name
        System.out.println(Ognl.getValue("name", student));
        System.out.println(Ognl.getValue("#root.name", student));

        /**
         * <pre>
         *     ognl可以写成链式的
         * </pre>
         */
        // 获取student的name的大写
        System.out.println(Ognl.getValue("name.toUpperCase()", student));

        /**
         * <pre>
         *     ognl 可以显示的指定使用context or root
         * </pre>
         */
        // 设置一个上下文
        System.out.println(Ognl.getValue("#context.student1.name", map, student));
        System.out.println(Ognl.getValue("#root.name", map, student));

        /**
         * <pre>
         *     context如果被添加之后, context里面的map都会变成跟root一个级别
         * </pre>
         */
        System.out.println(Ognl.getValue("#student1.name", map, student));

        /**
         * <pre>
         * 常量
         * 属性的引用 例如:user.name
         * 变量的引用 例如:#name
         * 静态变量的访问 使用 @class@field
         * 静态方法的调用 使用 @class@method(args), 如果没有指定 class 那么默认就使用 java.lang.Math.
         * 构造函数的调用 例如:new java.util.ArrayList();
         * </pre>
         */
        System.out.println(Ognl.getValue("@ongltest.Student@CODE", student));
        System.out.println(Ognl.getValue("@java.lang.Math@abs(-1)", student));

        /**
         * <pre>
         *  ognl可以set值
         * </pre>
         */
        Ognl.setValue("name", student, "gc2");
        System.out.println(Ognl.getValue("name", student));

        /**
         * <pre>
         *     ognl 还可以使用表达式判断
         * </pre>
         */
        System.out.println(Ognl.getValue("#root.phone.{? #this.equals('12345')}", student));
        System.out.println(Ognl.getValue("#root.phone.{? #this.equals('12345')}[0]", student));
        System.out.println(Ognl.getValue("#root.{ #this.phone.size > 1 ? #this.phone[1] : #this.phone[0] }", student));
    }
}