Arthas 命令
下载地址
下载地址:Releases · alibaba/arthas · GitHub
参考官方文档:https://arthas.aliyun.com/doc/quick-start.html
使用版本arthas-all-3.6.0版本,windows环境下使用
解压到指定目录 /xx/xx/arthas/
详情如下图
启动Arthas
Windows 控制台 cmd
cd /xx/xx/arthas/
启动命令 java -jar arthas-boot.jar
启动后如下图
蓝色方框表示java进程下标,输入下游即可进入相关java进程
如下图
红色方框表示 java 进程ID,如上图
默认30分钟后会自动退出session
常用命令及操作
dashboard-查看进程面板
memory-查看内存使用情况
jvm-查看JVM使用情况
MACHINE-NAME | 机器名称 |
JVM-START-TIME | JVM开始时间 |
MANAGEMENT-SPEC-VERSION | 管理规范版本 |
SPEC-NAME | 规范名称 |
SPEC-VENDOR | 规范供应商 |
SPEC-VERSION | 规范版本 |
VM-NAME | 虚机供应商 |
VM-VENDOR | 虚机供应商 |
VM-VERSION | 虚机版本 |
INPUT-ARGUMENTS | 输入编码 |
CLASS-PATH | CLASS路径 |
BOOT-CLASS-PATH | 引导类路径 |
LIBRARY-PATH | Jar库路径 |
CLASS-LOADING | 类加载 |
LOADED-CLASS-COUNT | 加载类计数 |
TOTAL-LOADED-CLASS-COUNT | 总加载类计数 |
UNLOADED-CLASS-COUNT | 未加载类计数 |
IS-VERBOSE | 是否详细 |
GARBAGE-COLLECTORS | 垃圾回收器 |
PS Scavenge | PS清除 |
PS MarkSweep | PS 标记清除 |
MEMORY-MANAGERS | 内存管理器 |
CodeCacheManager | 代码缓存管理器 |
Metaspace Manager | 元空间管理器 |
HEAP-MEMORY-USAGE | 堆内存使用情况 |
NO-HEAP-MEMORY-USAGE | 非堆内存使用情况 |
PENDING-FINALIZE-COUNT | 等待完成数 |
OPERATING-SYSTEM | 操作系统 |
THREAD -> COUNT | JVM当前活跃的线程数 |
THREAD -> DAEMON-COUNT | JVM当前活跃的守护线程数 |
THREAD -> PEAK-COUNT | 从JVM启动开始曾经活着的最大线程数 |
THREAD -> STARTED-COUNT | 从JVM启动开始总共启动过的线程次数 |
THREAD -> DEADLOCK-COUNT | JVM当前死锁的线程数 |
FILE-DESCRIPTOR | 文件描述符 |
MAX-FILE-DESCRIPTOR-COUNT | JVM进程最大可以打开的文件描述符数 |
OPEN-FILE-DESCRIPTOR-COUNT | JVM当前打开的文件描述符数 |
sysprop-查看,修改系统参数
sun.desktop awt.toolkit file.encoding.pkg java.specification.version sun.cpu.isalist sun.jnu.encoding java.class.path java.vm.vendor sun.arch.data.model user.variant java.vendor.url user.timezone os.name java.vm.specification.version user.country sun.java.launcher sun.boot.library.path sun.java.command sun.cpu.endian user.home user.language java.specification.vendor java.home file.separator line.separator java.vm.specification.vendor java.specification.name java.awt.graphicsenv sun.boot.class.path user.script sun.management.compiler java.runtime.version user.name path.separator os.version java.endorsed.dirs java.runtime.name file.encoding java.vm.name java.vendor.url.bug java.io.tmpdir java.version user.dir os.arch java.vm.specification.name java.awt.printerjob sun.os.patch.level java.library.path java.vm.info java.vendor java.vm.version java.ext.dirs sun.io.unicode.encoding java.class.version |
sysprop查看所有系统属性
sysprop key 查看单个系统属性
sysprop key value 修改单个系统属性
sysenv-查看当前JVM的环境属性
sysenv 查看所有jvm环境变量
sysenv key 查看单个jvm环境变量
vmoption 查看,更新jvm参数
HeapDumpBeforeFullGC HeapDumpAfterFullGC HeapDumpOnOutOfMemoryError HeapDumpPath CMSAbortablePrecleanWaitMillis CMSWaitDuration CMSTriggerInterval PrintGC PrintGCDetails PrintGCDateStamps PrintGCTimeStamps PrintGCID PrintClassHistogramBeforeFullGC PrintClassHistogramAfterFullGC PrintClassHistogram MinHeapFreeRatio MaxHeapFreeRatio PrintConcurrentLocks UnlockCommercialFeatures | 在FullGC前生产dump文件 在FullGC后生产dump文件 在oom异常时生成dump文件 指定dump文件路径 CMS可采用预清除等待时间毫秒 CMS间隙等待时间 CMS 触发间隔 打印GC日志 打印GC详情 打印GC日志时间戳 打印此次垃圾回收距离jvm开始运行的所耗时间 打印GCID 在FullGC前将内存中的对象以日志的形式输出 在FullGC后将内存中的对象以日志的形式输出 遇到 Ctrl-Break 后打印类实例的柱状信息 空闲堆空间最小占比 空闲堆空间最大占比 遇到Ctrl-Break后打印并发锁的相关信息 解锁商业功能 |
vmoption 查看所有JVM参数
vmoption key 查看单个jvm参数
vmoption key value 修改jvm属性信息
classLoader 查看classloader的继承树,urls,类加载信息
classLoader -l 查看类加载实例统计数据
classLoader -t 查看类加载器树形结构
classLoader -c hashcode 查看加载器加载jar的urls
jad 反编译指定已加载类的源码
jad .class 查看反编译源码,包含classLoader,重新编译.class
jad --source-only .class 查看只源码不显示classLoader
jad --source-only .class method --lineNumber false
查看某方法源码不显示行号
sc 查看jvm类加载信息
sc -d class 查看类属性信息
下图红框为类加载器
sc -d -f class 查看类信息,属性信息
sc -d class |grep key 查看某个类属性信息
mc 将.java文件编译成 .class 文件
mc xxx.java -d path 指定文件编译保存地址
mc -c hashcode xxx.java -d path 指定类加载器编译
retransform 加载外部的.class文件,覆盖jvm已加载的类
retransform path 指定重新加载外部.class文件
retransform的限制
- 不允许新增加field/method
- 正在跑的函数,没有退出不能生效,如下图mian()不生效,test()生效
- 重复多次加载同一个 .class 文件 id最大生效
retransform -l 统计所有重新加载 .class文件
retransform -d id编号 删除重载的.class文件 -d ID编号 retransform --deleteAll 删除全部
retransform --classPattern xxx.class 文件 重新回复编译文件
watch java方法执行数据观测
注:
观察表达式, 返回时的 {参数, this对象, 返回值}
观察表达式,默认值是{params,
target,
returnObj}
-x 查看层级,-n 查看次数
watch class method 实时查看指定类的方法入参和出参,持续打印结果
实时查看耗时大于10毫秒数据,查看一次展示5层级参数
watch class method "{params,returnObj,throwExp}" '#cost>10' -x 5 -n 1
实时查看耗时大于10毫秒且第一个数据等于1的数据,查看一次展示5层级参数
watch class method "{params,returnObj,throwExp}" '#cost>10 && params[0]==1' -x 5 -n 1
实时查看第一个数据大于1且第二个数据等于“hello”的数据,查看一次展示5层级参数
watch class method "{params,returnObj,throwExp}" 'params[0]>1 && params[1]=="hello"' -x 5 -n 1
实时查看第一个数据小于5或者 第二个数据等于“world”的数据,查看一次展示5层级参数
watch *.CommonTest test "{params,returnObj,throwExp}" 'params[0]<5 || params[1]=="wolrd"' -x 5 -n 1
trace 方法内部调用路径及耗时
trace class method 查看指定类调用链及耗时
ts=2022-04-22 15:24:01; 系统执行时间
thread_name=main;id=1; 线程名称,线程ID
is_daemon=false;priority=5; 是否守护线程,权重
TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2 类加载器
`---[0.1172ms] fills.arthas.ArthasTest:test() 执行时间
stack 输出当前方法被调用的调用路径
stack class method 查看指定类方法所有调用路径
ts=2022-04-22 15:37:02; 系统执行时间
thread_name=main;id=1; 线程名称,线程ID
is_daemon=false;priority=5; 是否守护线程,权重
TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2 类加载器
@fills.arthas.ArthasTest.test()
at fills.arthas.ArthasTest.main(ArthasTest.java:9) 调用链
ognl 调用静态属性和方法
1.查看静态属性
ognl ‘@全路经类名@属性字段’ -x 1 查看字段一级属性值
2.查看静态方法
ognl ‘@全路经类名@方法名称(xx,xx)’ -x 1 调用静态方法查看一级返回值; 2,3查看二,三级参数
案例场景应用
调用链接口新性能损耗分析
trace class method 实时抓取调用类方法请求及调用链处理时耗
注trace 每次只能查看一级链路耗时情况
trace com.ddky.top.meituan.web.controller.product.ProductManageController
listProductMapping
从调用链耗时情况可以看出是在调用dubbo服务耗时最多
+---[227.5465ms] com.ddky.top.meituan.service.ProductManageService:listProductManage() #140
trace com.ddky.top.meituan.service.ProductManageService listProductManage
+---[19.0228ms] com.ddky.top.meituan.data.dao.ProductManageDao:countProductMapping() #128
+---[9.3109ms] com.ddky.top.meituan.data.dao.ProductManageDao:listProductMapping() #132
+---[79.1293ms] com.ddky.top.inner.api.service.InnerProductClient:getPageFromCondition() #167
调用外部dubbo耗时
+---[63.7842ms] com.ddky.top.meituan.service.ProductPriceService:newReadBatchGetTopPrice() #171
循环内部接口调用耗时
从上图看出主要耗时地方有2处
建议优化方案
调用外部dubbo接口异步处理
调用内部循环调用改为批量查询
在线修改源码并热发布迅速解决线上问题
原有逻辑操作
- jad --source-only .class --lineNumber false > xxx.java 打印源码到指定文件
- vi xxx.java 修改源码
- sc .class |grep classLoaderHash 查看源码类加载器hashcode
- mc -c hashcode .java -d path 生成新的.class 文件
注(1-4步)可以线下生成class文件上传线上服务器,复杂的类编译很容易出错,不建议
5.retransform class 重新加载类文件
6.jad class 或者 retransform --classPattern class 重新加载源class文件复原线上环境
在线查看修改静态方法及属性值
1.查看线上静态配置属性
ognl ‘@全路经类名@属性字段’ -x 1 查看字段一级属性值
2.调用线上静态方法
ognl ‘@全路经类名@方法名称(xx,xx)’ -x 1 调用静态方法查看一级返回值
3.修改静态属性变量
ognl ‘@全路经类名@方法名称(xxx)’ 注: 该方法内部未修改属性
修改日志等级
1.logger --name ROOT --level debug 修改日志等级为debug
2. logger -c 2a139a55 --name ROOT --level debug 指定classloader更新日志等级为debug
略
还有其他运维场景比如修改jvm,系统环境参数,查看线上线程内存使用情况