news 2026/7/17 13:39:15

【JVM】Arthas相关分析命令

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【JVM】Arthas相关分析命令

【JVM】Arthas相关分析命令

  • 【一】下载和启动
  • 【二】JVM相关的核心功能
      • (1)类别 1:JVM基础信息监控
      • (2)类别 2:类与类加载器信息
      • (3)类别 3:性能分析与火焰图
  • 【三】JVM相关的命令
    • 【1】JVM相关命令
        • (1)dashboard:实时数据面板
        • (2)Thread:线程相关堆栈信息
        • (3)jvm
        • (4)sysprop:查看/修改属性
        • (5)sysenv:查看JVM环境属性
        • (6)vmpotion:查看JVM中选项
        • (7)getstatic:获取静态成员变量
        • (8)ognl:执行ognl表达式
    • 【2】类和类加载器(class/classLoader)
        • (1)sc:查看类信息
        • (2)sm:查看已加载方法信息
        • (3)编译与反编译jad、mc、redefine
        • (4)dump:保存已加载字节码文件到本地
        • (5)classloader:获取类加载器的信息
  • 【四】JVM分析案例
        • (1)准备测试的案例代码(死锁、内存泄漏多种情况、死循环)
        • (2)运行代码,启动arthas
        • (3)排查定位CPU飙高问题(死循环)
        • (4)排查定位死锁问题(死锁)

【一】下载和启动

下载地址:https://arthas.aliyun.com/doc/download.html

直接下载全量包

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

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

(1)用 as.sh 启动

解压后,在文件夹里有as.sh,直接用./as.sh的方式启动:

./as.sh

打印帮助信息:

./as.sh-h

(2)用 arthas-boot 启动
或者在解压后,在文件夹里有arthas-boot.jar,直接用java -jar的方式启动:

java-jar arthas-boot.jar

打印帮助信息:

java-jar arthas-boot.jar-h

(3)注意
在Linux上启动arthas的时候,要注意是不是root权限,并且注意项目启动的用户和当前启动arthas的用户是不是相同

【二】JVM相关的核心功能

(1)类别 1:JVM基础信息监控

(1)dashboard: ​核心命令。提供一个实时更新的仪表盘,一站式查看:

1-线程信息(显示CPU占用高的线程)
2-内存信息(堆内存、元空间等使用情况)
3-垃圾回收(GC)次数和时间
4-主机信息(CPU、负载)
5-运行时信息
6-​作用​:快速对应用的健康状况有一个整体了解,快速发现资源瓶颈。

(2)jvm: 查看详细的JVM信息,包括线程、内存、GC、加载类、操作系统等信息。
作用​:深入了解JVM的详细配置和状态。

(3)thread: 查看所有线程的信息,以及单个线程的堆栈。
1-thread : 查看指定线程的堆栈,非常适合定位CPU飙升问题。
2-thread -b: 直接找出阻塞其他线程的根因线程​(查找死锁)。
3-作用​:诊断线程相关问题,如CPU占用高、死锁、响应慢。

(4)sysenv/ sysprop: 查看系统的环境变量和JVM的系统属性。
作用​:确认应用运行时读取的配置是否正确,例如Spring的active profile、数据库连接地址等。

(2)类别 2:类与类加载器信息

(1)sc(Search Class)​: 查看已加载的类信息,包括来源哪个Jar包。
1-sc -d com.example.MyClass: 显示类的详细信息,包括其类加载器。
2-​作用​:排查类冲突(如NoSuchMethodError, NoClassDefFoundError),确认加载的类版本是否正确。

(2)​sm(Search Method)​: 查看类的方法信息。
1-sm com.example.MyClass *Method: 列出类中所有的方法。
2-​作用​:确认方法是否存在,以及它的描述符。

(3)​classloader: 查看类加载器的继承树、加载了哪些类、是否存在重复的Jar包或类。
1-​作用​:深入诊断类加载冲突、内存泄漏(类加载器无法被GC会导致其加载的所有类都无法卸载)。

(3)类别 3:性能分析与火焰图

(1)​profiler: 生成火焰图​(Flame Graph),一种非常直观的性能分析图表。
1-profiler start: 开始采样。
2-profiler stop: 停止采样并生成火焰图文件。
3-​作用​:从宏观上定位CPU占用热点,直观地看到代码的“火”(最耗CPU)在哪里。

【三】JVM相关的命令

【1】JVM相关命令

(1)dashboard:实时数据面板

查看当前系统的实时数据面板。

dashboard

输入 q 或者 Ctrl+C 可以退出dashboard命令
数据说明:

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

线程相关堆栈信息。

(1)Arthas支持管道,可以用 thread 1 | grep ‘main(’ 查找到main class。

thread 1|grep'main('
thread# 显示所有线程的信息thread 1# 显示1号线程的运行堆栈thread-b# 查看阻塞的线程信息thread-n 3# 查看最忙的3个线程,并打印堆栈thread-i 1000-n 3# 指定采样时间间隔,每过1000毫秒采样,显示最占时间的3个线程
查看处于等待状态的线程(WAITING、BLOCKED) thread--state WAITING

(2)死锁线程查看

thread# 查看线程状态thread-b# 查看阻塞的线程信息

(3)jvm

THREAD相关

COUNT:JVM当前活跃的线程数 DAEMON-COUNT: JVM当前活跃的守护线程数 PEAK-COUNT:从JVM启动开始曾经活着的最大线程数 STARTED-COUNT:从JVM启动开始总共启动过的线程次数 DEADLOCK-COUNT:JVM当前死锁的线程数

文件描述符相关

MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
(4)sysprop:查看/修改属性
sysprop# 查看所有属性sysprop java.version# 查看单个属性,支持通过tab补全

修改某个属性

sysprop user.country user.country=US
(5)sysenv:查看JVM环境属性

查看当前JVM的环境属性(System Environment Variables)

# 查看所有环境变量sysenv# 查看单个环境变量sysenv USER
(6)vmpotion:查看JVM中选项

查看JVM中选项,可以修改

# 查看所有的选项vmoption# 查看指定的选项vmoption PrintGCDetails# 更新指定的选项vmoption PrintGCDetails true

更新某一个值

(7)getstatic:获取静态成员变量

获取静态成员变量

# 语法getstatic 类名 属性名# 显示demo.MathGame类中静态属性randomgetstatic demo.MathGame random

(8)ognl:执行ognl表达式

执行ognl表达式,这是从3.0.5版本新增的功能。
(1)调用静态函数

# 获取系统变量中值,并且打印(只会打印有返回值函数)ognl'@java.lang.System@out.println("hello")'

(2)获取静态类的静态字段

# 获取代码中的运行返回值ognl'@demo.MathGame@random'

(3)执行多行表达式,赋值给临时变量,返回一个List

# 计算value1、value2值,并存在List集合中ognl'#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'

【2】类和类加载器(class/classLoader)

(1)sc:查看类信息

查看类的信息(sc: Search Class)

查看JVM已加载的类信息,“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息

sc 默认开启了子类匹配功能,也就是说所有当前类的子类也会被搜索出来,想要精确的匹配,请打开options disable-sub-class true开关。

# 模糊搜索,demo包下所有的类scdemo.*# 打印类的详细信息sc-d demo.MathGame

(2)sm:查看已加载方法信息

查看已加载方法信息(“Search-Method” )

查看已加载类的方法信息“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息。

sm 命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。

# 显示String类加载的方法sm java.lang.String# 查看方法信息sm demo.MathGame# 查看方法信息(详细信息-d)sm-d demo.MathGame

(3)编译与反编译jad、mc、redefine

(1)jad:反编译已加载类源码
反编译指定已加载类源码,jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便。当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解。

# 反编译MathGame方法jad demo.MathGame# 反编绎时只显示源代码(排除ClassLoader信息)。# 默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。jad--source-only demo.MathGame# 反编译到指定文件中jad--source-only demo.MathGame > Hello.java# 只反编译mathGame类型中main方法jad demo.MathGame main


(2)mc:编译Java代码
内存编译,Memory Compiler/内存编译器,编译.java文件生成.class

# 在内存中编译Hello.java为Hello.classmc/root/Hello.java# 可以通过-d命令指定输出目录mc-d/root/bbb/root/Hello.java


(3)redefine:加载外部.class文件
加载外部的.class文件,redefine到JVM里。

注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field)。
reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码。
redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。

redefine的限制

(1)不允许新增加field/method
(2)正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有run()函数里的会生效。

# 1. 使用jad反编译demo.MathGame输出到/root/MathGame.javajad--source-only demo.MathGame >/root/MathGame.java# 2.按上面的代码编辑完毕以后,使用mc内存中对新的代码编译mc/root/MathGame.java-d/root# 3.使用redefine命令加载新的字节码redefine/root/demo/MathGame.class

(4)dump:保存已加载字节码文件到本地

将已加载类的字节码文件保存在特定目录:logs/arthas/classdump。不同的类加载器放在不同的目录下。dump作用:将正在JVM中运行的程序的字节码文件提取出来,保存在logs相应的目录下

# 把String类的字节码文件保存到~/logs/arthas/classdump/目录下dump java.lang.String# 把demo包下所有的类的字节码文件保存到~/logs/arthas/classdump/目录下dump demo.*
(5)classloader:获取类加载器的信息

获取类加载器的信息

作用:
(1)classloader 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。
(2)可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于ResourceNotFoundException异常比较有用。

# 默认按类加载器的类型查看统计信息classloader

# 按类加载器的实例查看统计信息,可以看到类加载的hashCodeclassloader-l

# 查看ClassLoader的继承树classloader-t

# 通过类加载器的hash,查看此类加载器实际所在的位置classloader-c 680f2737

# 使用ClassLoader去查找指定资源resource所在的位置classloader-c 680f2737-r META-INF/MANIFEST.MF

# 使用ClassLoader去查找类的class文件所在的位置classloader-c 680f2737-r java/lang/String.class

# 使用ClassLoader去加载类classloader-c 70dea4e--load java.lang.String

classloader命令主要作用有哪些?
(1)显示所有类加载器的信息
(2)获取某个类加载器所在的jar包
(3)获取某个资源在哪个jar包中
(4)加载某个类

【四】JVM分析案例

(1)准备测试的案例代码(死锁、内存泄漏多种情况、死循环)
publicclassjvmUpdate02{privatestaticHashSethashSet=newHashSet();publicstaticvoidmain(String[]args){//模拟死锁deadThread();//创建对象addHashSetThread();//模拟高CPUcpuHigh();}/** 模拟死锁 * @MethodName: deadThread * @Author: AllenSun * @Date: 2022/11/9 上午12:59 */privatestaticvoiddeadThread(){Objectlock1=newObject();Objectlock2=newObject();newThread(()->{synchronized(lock1){try{System.out.println("线程1启动");Thread.sleep(5000);}catch(InterruptedExceptione){e.printStackTrace();}synchronized(lock2){System.out.println("线程1结束");}}}).start();newThread(()->{synchronized(lock2){try{System.out.println("线程2启动");Thread.sleep(5000);}catch(InterruptedExceptione){e.printStackTrace();}synchronized(lock1){System.out.println("线程2结束");}}}).start();System.out.println("主线程结束");}/**不断的向HashSet集合添加数据 * @MethodName: addHashSetThread * @Author: AllenSun * @Date: 2022/11/9 上午1:03 */publicstaticvoidaddHashSetThread(){newThread(()->{intcount=0;while(true){try{hashSet.add("count"+count);Thread.sleep(10000);count++;}catch(InterruptedExceptione){e.printStackTrace();}}}).start();}/** 模拟CPU飙升 * @MethodName: cpuHigh * @Author: AllenSun * @Date: 2022/11/9 上午1:05 */publicstaticvoidcpuHigh(){newThread(()->{while(true){}}).start();}}
(2)运行代码,启动arthas

先运行代码,然后启动arthas:java -jar arthas-boot.jar

(3)排查定位CPU飙高问题(死循环)

(1)输入dashboard:仪表盘,内存使用情况综合界面
可以看出来下面线程id为14的线程占用的CPU较高,接下来对其进行分析

(2)thread 线程id:查看问题线程的具体情况
ctrl+c退出仪表盘
thread 14查看对应线程的情况

找到92行,果然看到方法体中有一个无限循环,导致了CPU飙高

(3)thread -n 1:列出CPU占用前1的线程

(4)排查定位死锁问题(死锁)

(1)thread -b:定位死锁问题出现的位置

定位到42行,这个lock2在下面被尝试获取失败导致产生的死锁

(2)thread,获取所有线程的情况
根据状态State的字段【BLOCKED】可以找到具体产生死锁的方法

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 13:38:55

收藏!前端程序员进阶必看:AI时代如何抓住四大发展机遇?

AI技术快速发展,前端开发面临被淘汰风险。文章提出四条进阶路径:1)全栈开发,需掌握前后端工程、数据库、部署等综合能力;2)AI大模型应用开发,重点在于将模型能力转化为稳定产品;3&am…

作者头像 李华
网站建设 2026/7/17 13:38:25

开发者必读:numafast贡献指南与代码提交流程

开发者必读:numafast贡献指南与代码提交流程 【免费下载链接】numafast numafast is a userspace tool designed for Kunpeng Chips that aims to improve system performance by reducing cross-NUMA memory access. 项目地址: https://gitcode.com/openeuler/nu…

作者头像 李华
网站建设 2026/7/17 13:35:39

CANN/Ascend C: SetCtrlSpr控制寄存器设置

SetCtrlSpr(ISASI) 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitc…

作者头像 李华
网站建设 2026/7/17 13:35:03

电子滤波电路设计:从基础原理到实战应用

1. 滤波电路基础概念与分类在电子电路设计中,滤波电路就像是一个智能的交通警察,负责指挥不同频率的信号各行其道。它的核心任务是从复杂的混合信号中分离出我们需要的部分,同时阻挡或衰减不需要的成分。这种"信号筛选"能力在几乎所…

作者头像 李华
网站建设 2026/7/17 13:34:10

tschema错误处理最佳实践:构建健壮的API验证系统

tschema错误处理最佳实践:构建健壮的API验证系统 【免费下载链接】tschema A tiny (500b) utility to build JSON schema types. 项目地址: https://gitcode.com/gh_mirrors/ts/tschema 在构建现代Web应用和API时,数据验证是确保系统稳定性的关键…

作者头像 李华