Arthas是一个java在线诊断工具,能够分析、诊断、定位java应用问题。之前余梦同学对Arthas的使用写过一篇文章在线分析诊断工具Arthas简介及使用,所以具体使用方法我就不重复叙述了。接下来我将详细地分析下arthas是如何实现对java程序的分析和诊断的。

前言

Arthas是一个功能非常强大的诊断工具,功能点很多,例如:jvm信息、线程信息、搜索类中的方法、跟踪代码执行、观测方法的入参和返回参数等等。这些会驱使你去了解它是如何做到的。在这之前你可能还需要了解一些额外的知识,例如ava SE 5中增加的特性Instrumentation、ASM字节码增强技术。

Instrumentation把 Java的instrument 功能从本地代码中解放出来,使之可以用Java代码的方式解决问题。使用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。Instrumentation是Java SE 5中的新特性。在SE 5中只能在运行前进行加载,在SE 6中实现能够在运行时加载。例如java -javaagent: agent.jar -jar agent-demo.jar
ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。asm字节码增强技术主要是用来反射的时候提升性能的,如果单纯用jdk的反射调用,性能是非常低下的,而使用字节码增强技术后反射调用的时间已经基本可以与直接调用相当。
ASM相对于其他类似工具如BCEL、SERP、Javassist、CGLIB,它的最大的优势就在于其性能更高,其jar包仅30K。Hibernate和Spring都使用了cglib代理,而cglib本身就是使用的ASM,可见ASM在各种开源框架都有广泛的应用。  ASM框架中的核心类有以下几个:①  ClassReader:该类用来解析编译过的class字节码文件。②  ClassWriter:该类用来重新构建编译后的类,比如说修改类名、属性以及方法,甚至可以生成新的类的字节码文件。③  ClassAdapter:该类也实现了ClassVisitor接口,它将对它的方法调用委托给另一个ClassVisitor对象。

启动剖析

1.通过as.sh进行启动 
* parsearguments 解析用户输入参数,并获取用户输入的pid * attachjvm对选中的java程序进行挂载 * active_console 启动arthas的客户端,显示命令行界面

其中attach_jvm是其中最核心的功能点,它的主要作用是启动arthas-core.jar在arthas-core中主要的功能其实就是加载agent.jar到对应的java程序中上图可以看出,程序先用获取所有java的VirtualMachine,根据已知的pid找到对应的VirtualMachine,然后进行VirtualMachine.loadAgent加载arthas.jar。这里加载agent在主程序启动之后获取pid进行运行后加载的,这个特性是Java SE 6的新特性。可以在运行后对加载的class进行重加载。

加载Agent

想要理解虚拟机如何加载agent,那么就需要找到agent的启动方法,并理解agent如何对运行时的class进行修改。 找到com.taobao.arthas.agent.AgentBootstrap这个类,它是agent的启动类。上面图片中显示了premain和agentmain两个方法。这两个方法有些不同,premain方法用于运行前的agent加载,agentmain用于运行时的加载。在arthas中使用的是agentmain方法。 那么jar是怎么封装成agent进行使用的呢?可以打开pom.xml文件,使用assembly进行打包的时候制定了manifest文件的一些信息

回到AgentBootstrap类,agentmain方法里面调用了main方法。从上图可知,main方法实现以下几点功能

  • 获取arthas-spy.jar,用bootstrapClassLoader进行加载
  • 创建自定义的类加载器
  • 初始化探针,加载com.taobao.arthas.core.advisor.AdviceWeaver中的methodOnBegin、methodOnReturnEnd、methodOnThrowingEnd等等方法(下面章节将具体介绍为何要加载探针和AdviceWeaver中的方法)
  • 加载com.taobao.arthas.core.server.ArthasBootstrap,调用bind方法,启动server服务

启动server

上图图片中根据telnetPort判断是否启动telnet服务,根据httpPort判断是否启动http服务。

下面以TelnetTermServer服务为例进行分析当有命令过来时,通过termHandler.handle进行处理。 这里的termHandler来自于上一步设置的TermServerTermHandlerhandle方法中使用shellServer进行处理,而这里的shellServer实际上是ShellServerImpl这个类 
ShellServerImpl中handleTerm用于处理客户端的连接 
这里的session就是客户端的连接,readline会等待客户端的输入。

命令执行

深入readline方法,我们会发现底层代码其实就是调用了ShellLineHandler.handle对命令进行处理。这里面的封装比较复杂,ShellLineHandler.handle->RequestHandler.accept->Interaction.end,最终封装成Interaction进行处理,这里就不一一罗列。仔细研读ShellLineHandler.handle中的代码,我们会发现每个用户请求,arthas都会封装成job。job根据命令名称从commandManager获取预设的command进行执行,而BuiltinCommandPack里面加载了所有的命令 
最后进行命令的执行

Command分析

arthas里面预设了很多的命令,接下来我们将根据WatchCommand进行详细分析。除了需要字节码增强的命令外其他的命令比较简单,主要是使用java.lang.management包的类来获取虚拟机信息。

WatchCommand 
WatchCommand主要用于观测方法的入参和返回参数信息,以及方法的耗时统计。使用ASM字节码技术对特定class进行字节码增强,并重新加载class使之生效。因此在研读这个命令之前请先了解ASM和class文件规范。public class WatchCommand extends EnhancerCommand,WatchCommand继承于EnhancerCommand。 
详细查看EnhancerCommand.enhance方法中的Enhancer.enhance方法。1.筛选出需要增强的类,根据className进行条件过滤。2.构建增强器。3.Instrumentation.retransformClasses重新加载类,重新加载时会触发ClassFileTransformer.transform方法,对指定的类进行字节码编辑EnhancerAdviceWeaver类实现了ClassVisitor接口。ClassVisitor接口的核心是visit和visitMethod,其中visitMethod是对类中每个方法的访问。 
visitMethod 
在visitMethod方法中,重写了一个AdviceAdapter类,继承了MethodVisitor类,实现对method的访问onMethodEnter 
在访问方法前执行onMethodEnter中的内容。调用loadAdviceMethod方法,根据里面的代码显示,实质是获取Spy这个类中的变量ONBEFOREMETHOD,通过ASM的方法进行调用。其中loadArrayForBefore方法是加载ONBEFOREMETHOD方法对应的参数,而ONBEFOREMETHOD这个方法对应的是AdviceWeaver类中的methodOnBegin方法。 
这一步在哪里设置的呢 
回到最开始的AgentBootstrap.initSpy方法,我们就可以发现。实际上spy这个类使用bootstrapClassLoader加载的,以确保之后能够在各个类加载器中能够被正确获取在这里不得不佩服开发人员的厉害之处,在一开始的初始化Spy的时候将Spy这类设置在根加载器中,确保自定义加载器都能够获取到这个类。通过spy这个类作为探针,用ASM获取到这个静态变量用loadArrayForBefore加载所需要的参数(需要对字节码指令、局部变量表、操作数栈有一定了解),最后使用invokeVirtual指令进行调用。ON_BEFORE_METHOD对应着methodOnBegin方法,其他暂不展示,以methodOnBegin为例。

  • 将主要信息放在栈中,并存入线程变量,在methodOnReturnEnd等方法中可以使用
  • 进行方法前置通知,listener在EnhancerCommand.enhance方法中注册。WatchComand对应的监听器是WatchAdviceListener。

WatchAdviceListener判断是否满足ognl表达式,如果满足,向客户端打印信息。这里仅仅是用methodBegin做分析,如果是methodExit即方法结束,也会进行后置通知,执行WatchAdviceListener.afterReturning方法。

总结

希望通过以上的分析,大家能够大致了解arthas运行的原理。通过arthas源码的研读,我们会找到一些有趣的东西,比如Instrumentation、ASM的用法。这些在以后工作中遇到问题时给我们带来启发。

Arthas源码分析相关推荐

  1. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  2. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  3. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  4. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  5. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

  6. ViewGroup的Touch事件分发(源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,View的touch事件分发相对比较简单,可参考 View的Touch事件分发(一.初步了解) View的Touch事 ...

  7. View的Touch事件分发(二.源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...

  8. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: Java代码   String res ...

  9. [转]slf4j + log4j原理实现及源码分析

    slf4j + log4j原理实现及源码分析 转载于:https://www.cnblogs.com/jasonzeng888/p/6051080.html

最新文章

  1. CPU状态信息us,sy,ni,id,wa,hi,si,st含义
  2. MySQL系列(二)
  3. Visual Studio 2012中的为创建类时的添加注释模板
  4. fastText原理和文本分类实战
  5. javascript精要(3)-动态加载脚本
  6. js mysql 时间日期比较
  7. python中的out of loop_TclError: out of stack space (infinite loop?)
  8. query上传插件uploadify参数详细分析
  9. Oracle 多表查询 --笛卡尔集--左连接--右连接--1999 语法--满外连接
  10. MySQL入门02-MySQL二进制版本快速部署
  11. SoftCnKiller高速下载器捆绑软件杀手
  12. Android小项目--2048小游戏
  13. 蓝牙厂商代码与公司对应列表
  14. navcat定时备份mysql_Navicat for MySQL定时备份数据库及数据恢复
  15. 看你想看的,不受打扰地工作(浏览器屏蔽百度热搜)
  16. 云计算机什么意思啊,什么叫云计算,云计算是什么,最通俗的解释是这样的
  17. Tesseract-OCR安装简明教程
  18. 计算机多媒体培训总结,多媒体培训心得体会
  19. 重装系统后电脑耳机插前面没有声音输出怎么办?
  20. linux的web服务

热门文章

  1. CAD多线怎么转换成多段线?
  2. 带电圆环matlab,利用MATLAB分析圆环电流的磁场分布
  3. 新闻稿怎么写?手把手教你撰写新闻稿
  4. c语言地理坐标存储 转发,从照片中批量导出GPS地理坐标信息
  5. 【基于MATLAB实现LSTM光伏输出功率预测】
  6. SuperMap许可常见问题及解决办法
  7. WebRTC学习进阶之路 --- 五、WebRTC网络知识详解(三)(最全流媒体协议(RTP/RTCP/RTSP/RTMP/MMS/HLS/HTTP/ HTTP-FLV(HDL)/SDP)
  8. C# NX二次开发:制图模块中尺寸线标注类型的type值和subtype值归纳总结
  9. 程序设计基础(CC++) 戴波、张东祥 第三章 控制语句 编程作业
  10. CSS权重问题导致的盒子右边距无法清除