• 四、Arthas


    四、Arthas

        1、安装/卸载

            (1)、Arthas支持在Linux/Unix/Mac等平台上一键安装,请复制以下内容,并粘贴到命令行中,敲回车执行即可。

    curl -L https://arthas.aliyun.com/install.sh | sh

                上述命令会下载启动脚本文件as.sh到当前目录,你可以放在任何地方或将其加入到$PATH中。直接在shell下面执行./as.sh,就会进入交互界面。也可以执行./as.sh -h来获取更多参数信息。

    Das

            (2)、卸载

                在Linux/Unix/Mac平台删除下面文件。

    rm -rf ~/.arthas/

    rm -rf ~/logs/arthas

        2、运行

            执行:java -jar arthas-boot.jar 运行Arthas,粘附到指定Java应用进程

        3、命令

            (1)、基础命令

                help——查看命令帮助信息

                cls——清空当前屏幕区域

                session——查看当前会话的信息

                reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类

                version——输出当前目标 Java 进程所加载的 Arthas 版本号

                history——打印命令历史

                quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响

                stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出

                keymap——Arthas快捷键列表及自定义快捷键

            (2)、常用命令

                命令列表:命令列表 | arthas

                ①、dashboard 查看仪表盘,按Q或Ctrl + C可以中断执行。

                ②、thread 获取该进程的所有线程

                    thread 1 查看序号为1线程的内容

                ③、jad java.lang.Object 反编译Object类方便查看

        4、源码分析

            (1)、arthas-boot模块

                ①、输入命令:java -jar arthas-boot.jar 或 ./as.sh

                ②、运行arthas-boot.jar中com.taobao.arthas.boot.Bootstrap#main方法,或者运行as.sh文件

                ③、获取arthas版本信息

                ④、解析命令传入参数,将参数解析成CommandLine对象

                ⑤、设置镜像仓库,日志打印等

                ⑥、端口校验是否被占用

                ⑦、获取pid,校验目标端口的pid和attach pid是否一致

                ⑧、获取arthas home,启动arthas-core.jar

            (2)、arthas-core模块

                ①、运行arthas-boot.jar中com.taobao.arthas.core.Arthas#main

                ②、将透传的参数解析转换成CommandLine对象

                ③、获取VirtualMachine.list()列表,匹配目标进程pid

                ④、利用VirtualMachine.attach(),attach到目标进程

                ⑤、利用virtualMachine.loadAgent()方法加载agent的jar包arthas-agent.jar 

            (3)、arthas-agent模块(从这开始所有代码都是运行在目标JVM中)

                ①、运行arthas-agent.jar中com.taobao.arthas.agent334.AgentBootstrap#main

                ②、对传递的参数解析

                ③、通过反射执行com.taobao.arthas.core.server.ArthasBootstrap#getInstance(Instrumentation ins, String args)方法,初始化spy和arthas命令

                ④、将arthas-spy.jar添加到BootstrapClassLoader加载目录下,解决一些ClassLoader加载不到SpyAPI的问题,加载SpyAPI,通过字节码插入到业务代码的逻辑类在arthas-spy.jar包

                ⑤、初始化arthas运行的环境变量

            (4)、arthas-spy.jar包

                ①、SpyAPI当中的6个“at…”静态方法都调用了实例spyInstance中对应的方法。spyInstance的静态类型是抽象类AbstractSpy,抽象类AbstractSpy当中有六个抽象方法。当SpyAPI被加载时,它的静态语句会将spyInstance设置为类NopSpy的实例,其中这NopSpy继承自AbstractSpy并且实现的每个方法都是空操作。

                ②、AbstractSpy抽象类

    1. public static abstract class AbstractSpy {
    2. // 进入
    3. public abstract void atEnter(Class clazz, String methodInfo, Object target, Object[] args);
    4. // 退出
    5. public abstract void atExit(Class clazz, String methodInfo, Object target, Object[] args, Object returnObject);
    6. // 异常退出
    7. public abstract void atExceptionExit(Class clazz, String methodInfo, Object target, Object[] args, Throwable throwable);
    8. // 调用前
    9. public abstract void atBeforeInvoke(Class clazz, String invokeInfo, Object target);
    10. // 调用后
    11. public abstract void atAfterInvoke(Class clazz, String invokeInfo, Object target);
    12. // 异常调用
    13. public abstract void atInvokeException(Class clazz, String invokeInfo, Object target, Throwable throwable);
    14. }

                ③、Enhancer类

                    对类进行通知增强,继承ClassFileTransformer,并实现transform方法

    1. public class Enhancer implements ClassFileTransformer {
    2. // 通过静态代码块初始化SpyAPI
    3. static {
    4. SpyAPI.setSpy(spyImpl);
    5. }
    6. @Override
    7. public byte[] transform(final ClassLoader inClassLoader, String className, Class classBeingRedefined,
    8. ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    9. try {
    10. // 检查classloader能否加载到 SpyAPI,如果不能,则放弃增强
    11. try {
    12. if (inClassLoader != null) {
    13. inClassLoader.loadClass(SpyAPI.class.getName());
    14. }
    15. } catch (Throwable e) {
    16. logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}",
    17. inClassLoader.getClass().getName(), className, e);
    18. return null;
    19. }
    20. }
    21. ...
    22. return null;
    23. }
    24. }

    参考文章:

            (1)、消失的堆栈:消失的堆栈

            (2)、JVM Attach机制:JVM Attach机制实现 - 你假笨

            (3)、Arthas原理一:Arthas原理系列(一):利用JVM的attach机制实现一个极简的watch命令

            (4)、Arthas原理二:Arthas原理系列(二):总体架构和项目入口

            (5)、Arthas原理三:Arthas原理系列(三):服务端启动流程

  • 相关阅读:
    机器学习面试中常见问题整理
    Debiased Contrastive Learning of Unsupervised Sentence Representations 论文阅读
    说说Alpha指令集和那些事儿
    background
    深入理解JVM虚拟机第十九篇:JVM字节码中方法内部的结构和与局部变量表中变量槽的介绍
    单片机:步进电机(内含:1 步进电机简介+2 步进电机工作原理+ 3 步进电机技术指标 +4. 软件设计+5.原始代码+6.实验现象)
    Centos7单机部署zookeeper与kafka整体步骤,附上安装测试
    mysql面试题——存储引擎相关面试题
    【HMS core】【FAQ】典型问题合集7
    Qt扫盲-QSqlQueryModel理论总结
  • 原文地址:https://blog.csdn.net/L_D_Y_K/article/details/126508278