news 2026/2/12 4:34:17

JVM 之 线上诊断神器Arthas【内部原理?常用命令?如何使用Arthas排查cpu飙高、类加载问题、死锁、慢接口等线上问题?】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM 之 线上诊断神器Arthas【内部原理?常用命令?如何使用Arthas排查cpu飙高、类加载问题、死锁、慢接口等线上问题?】

Arthas 是什么?

简单讲,他是一款开源的线上诊断工具
可以在,不重启应用的前提下,对服务进行实时监控,诊断,调试,甚至进行热修复

  • 官方文档:https://arthas.aliyun.com/doc/

Arthas 解决了什么问题?

  • 1、线上debug只能加日志-》打包-》重新部署-》等待复现。
  • 2、性能瓶颈(慢方法、cpu飙高、内存泄漏)难以定位
  • 3、类加载异常难定位(ClassNotFoundException、NoSuchMethodError等,不知道从哪加载的?是否被覆盖)
  • 4、逻辑调用链不清晰(方法被谁调用的?参数是什么?)
  • 5、紧急bug只能停机重新发布

适用场景

  • 适合:线上紧急问题、性能问题、类加载问题排查,以及临时调试
  • 不适合:因为Arthas需手动交互+数据不存储,所以不适合自动化或长期监控。

Arthas 是怎么解决的这些问题

说白了,Arthas利用了Java Agent+Bytecode Instrumentation(字节码增强)技术,
在运行时动态注入探针,实现对 JVM 内部状态的非侵入式观测与干预

Java Agent: 允许在不修改源代码、不重启应用的前提下,对程序进行监控、诊断、性能分析、日志增强、安全审计甚至热修复


Arthas提供了哪些能力?

能力说明
实时监控查看方法入参、返回值、异常(watch
性能剖析分析方法耗时、生成火焰图(trace/profiler
类信息查询查看类从哪个 JAR 加载、反编译字节码(sc/jad
热更新动态替换类定义,修复线上 Bug(redefine
JVM 全局视图实时查看线程、内存、GC、系统负载(dashboard
调用链追踪查看方法被谁调用、调用栈(stack

所有操作无需重启应用无需改代码秒级生效


Arthas如何使用?

1、安装(任选其一)

# 方式一:快速启动(推荐)curl-O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar# 方式二:脚本安装(Linux/macOS)curl-L https://arthas.aliyun.com/install.sh|sh./as.sh

2、启动

  1. 运行java -jar arthas-boot.jar-》列出当前机器上所有 Java 进程
  2. 输入目标进程的编号,进入 Arthas 命令行(提示符如[arthas@12364]$

启动时如指定 HTTP 端口java -jar arthas-boot.jar --http-port 8563,可在浏览器访问:http://<服务器IP>:8563图形化界面。


3、Arthas提供了哪些命令?

# 查看系统实时状态(线程、内存、GC)dashboard# 反编译某个类(确认线上代码是否正确)jad com.example.service.UserService# 监控方法入参和返回值(“这个方法执行时参数/返回值/异常是什么?” → 监控 方法内部数据)watchcom.example.service.UserService login'{params, returnObj}'-x2# 追踪方法调用耗时(定位慢接口)trace com.example.controller.UserController getUser# 查看某个方法的调用栈(“谁调用了这个方法?” → 查看 调用栈(Call Stack))stack com.example.service.UserService saveUser# 动态修改日志级别(无需重启)logger --name com.example.service.UserService --level debug# 搜索已加载的类sc *UserService*# 搜索类的方法sm com.example.service.UserService *# 生成火焰图(需 profiler 支持)profiler start# ...等待几秒...profiler stop

如何使用Arthas进行线上具体场景问题排查?

发现现象 → 确定排查思路 → 使用Arthas排查 → 解决问题

常见场景速查表

问题类型关键命令核心输出
CPU 100%thread -n 3jadprofiler高 CPU 线程 + 热点代码
死锁thread -b死锁线程对 + 锁依赖关系
慢接口tracewatchstack耗时分布 + 参数/异常
类加载问题scjadclassloader类加载情况 + 类反编译内容

场景一:CPU飙高

现象

  • 1、应用响应变慢甚至无响应
  • 2、服务器负载飙升,top显示某个 Java 进程 CPU 占用接近 100%

排查思路

CPU飙高,通常是因为无限循环、正则回溯、复杂计算等引起的。
所以排查思路是:

  • 1、找出哪个线程在疯狂占用 CPU?
  • 2、这个线程在执行什么代码?

Arthas排查定位步骤

  • 1、启动 Arthas 并 attach 到目标进程java -jar arthas-boot.jar 并进入目标服务进程
  • 2、查看 CPU使用率最高 的前 3 个线程thread -n 3
    关键信息:线程名Thread-10,ID=45,CPU占用 98.7%,卡在DataProcessor.java:28
    执行后,输出示例如下: Threads Total: 50, NEW: 0, RUNNABLE: 10, BLOCKED: 0, WAITING: 20, TIMED_WAITING: 20 "Thread-10" Id=45 cpuUsage=98.7% RUNNABLE at com.example.service.DataProcessor.process(DataProcessor.java:28) at com.example.service.DataProcessor.lambda$start$0(DataProcessor.java:15) ...
  • 3、反编译该类确认代码逻辑(是否有死循环或低效算法)jad com.example.service.DataProcessor
    例如:while(true){// ← 问题在这里!list.add(newObject());}
  • 4、生成火焰图,并下载到本地,用浏览器打开,观察其中的热点方法。
    profiler start# 等待 10 秒,然后输出结果文件 arthas-output/xxx.htmlprofiler stop --format html
  • 5、定位到具体原因,修改后重新部署

场景二:死锁(Deadlock)

现象

  • 1、请求全部超时(应用完全卡住)
  • 2、日志中无异常信息,但日志不再输出(线程不再处理新任务)

排查思路

死锁通常由多个线程互相持有对方需要的锁导致。JVM 能自动检测死锁。

Arthas排查定位步骤

  • 1、启动 Arthas 并 attach 到目标进程java -jar arthas-boot.jar 并进入目标服务进程
  • 2、检查是否存在死锁thread -b

    -b参数表示detect deadlock(检测死锁)

    • 存在死锁则会输出死锁的具体信息:(以下Thread-A、Thread-B相互引用,典型死锁)
    Found one Java-level deadlock: ============================= "Thread-A": waiting to lock monitor 0x00007f8b4c003a88 (object 0x000000076b8d1234, a java.lang.Object), which is held by "Thread-B" "Thread-B": waiting to lock monitor 0x00007f8b4c004b99 (object 0x000000076b8d1240, a java.lang.Object), which is held by "Thread-A" Java stack information for the threads listed above: =================================================== "Thread-A": at com.example.service.OrderService.pay(OrderService.java:30) - waiting to lock <0x000000076b8d1234> (a java.lang.Object) at com.example.controller.OrderController.submit(OrderController.java:22) ...
  • 3、查看完整线程栈
    thread# 查看所有线程状态# 或指定线程 IDthread45
  • 4、根据线程栈找出具体死锁位置及原因,并加以解决重新部署。

场景三:慢接口

现象

其他接口正常,只有某个接口响应时间暴涨(例如:100ms-》5s+)

排查思路

可能的原因:

  • 1、是不是数据库慢查询
  • 2、是不是调用的其他服务的http接口超时,进而导致的超时
  • 3、本地方法逻辑复杂(如大循环、序列化)

此时需要追踪整个调用链的耗时分布

Arthas排查定位步骤

假设慢接口对应 Controller 方法:com.example.controller.UserController.getUser

  • 1、使用trace命令追踪方法调用耗时trace com.example.controller.UserController getUser
    • 1.1、然后触发一次请求,使Arthas输出调用链路(如curl http://localhost:8080/user/123
      `---ts=2025-12-13 17:40:01;thread_name=http-nio-8080-exec-2;id=2a;is_daemon=true;priority=5;TCCL=org.springframework.boot... `---[5023.45ms] com.example.controller.UserController:getUser() +---[0.12ms] com.example.service.UserService::findById() +---[5022.89ms] com.example.service.NotificationService::sendEmail() # ← 耗时 5 秒! `---[0.05ms] return result
    • 1.2、分析调用链路,找出耗时原因。(例如上诉:sendEmail()花了 5 秒,可能是 SMTP 超时或网络问题。)
    • 1.3、重复上诉步骤,找到最终的那个慢方法。(例如:继续分析sendEmail方法内部,trace com.example.service.NotificationService sendEmail
  • 2、监控慢方法的参数和返回值,确定问题出现的原因。
    watchcom.example.service.NotificationService sendEmail'{params, returnObj, throwExp}'-v -x2## 可看到是否传入了错误邮箱、是否抛出异常等。
  • 3、可通过热更新,先保证线上服务可用(临时解决,应急,例如跳过该逻辑)
    • 3.1. 修改UserController.java,注释掉notificationService.sendEmail(...)
    • 3.2. 编译生成.class
    • 3.3. 执行:redefine /tmp/UserController.class
  • 4、根本上解决该问题,并发布更新。

场景四:类加载异常

现象

异常常见原因
ClassNotFoundException类根本不存在于 classpath
NoClassDefFoundError编译时存在,运行时缺失(如依赖未打包)
NoSuchMethodError方法签名不一致(通常是版本冲突:A 依赖 v1,B 依赖 v2)
IncompatibleClassChangeError类结构不兼容(如接口变抽象类)
LinkageError/ClassCastException同一个类被不同 ClassLoader 加载

排查思路

核心问题本质

  • 类找不到?→ 检查是否在 classpath
  • 类找到了但不对?→ 检查是否被错误版本覆盖
  • 同一个类加载了多份?→ 检查 ClassLoader 隔离问题

Arthas 排查思路(四步法):

  • 1、类是否被加载?→ 使用sc(Search Class)
  • 2、如果已加载,从哪加载的?→ 使用sc -d查看类的详细信息(含 ClassLoader 和 codeSource)
  • 3、反编译字节码,确认方法/字段是否存在?→ 使用jad查看实际加载的代码
  • 4、检查类加载器层次,分析是否存在冲突?→ 使用classloader命令分析 ClassLoader 树

Arthas排查定位详细步骤

假设有以下报错java.lang.NoSuchMethodError: com.example.util.StringUtils.isBlank(Ljava/lang/String;)Z
根据报错怀疑StringUtils被低版本 JAR 覆盖

  • 1、搜索该类是否被加载sc *StringUtils*
    • 发现存在两个StringUtils!需进一步确认用的是哪个:
    com.example.util.StringUtils org.apache.commons.lang3.StringUtils
  • 2、查看具体类的加载信息(关键!)sc -d com.example.util.StringUtils
    • 输出示例:(重点看code-sourceclass-loader
      class-info com.example.util.StringUtils code-source /app/lib/utils-1.0.jar ← ⚠️ 关键:来自哪个 JAR!判断是不是你所期望的那个?(`code-source` 为空,可能是从 `classes` 目录加载(非 JAR)) name com.example.util.StringUtils isInterface false isAnnotation false isEnum false isAnonymousClass false isArray false isLocalClass false isMemberClass false isPrimitive false isSynthetic false simple-name StringUtils modifier public annotation interfaces super-class java.lang.Object class-loader org.springframework.boot.loader.LaunchedURLClassLoader@1c20c6b4 class-loader-hash 1c20c6b4
  • 3、反编译确认方法是否存在:jad com.example.util.StringUtils
    • 例如以下输出片段:(没有isBlank方法,所以抛出NoSuchMethodError
    publicclassStringUtils{publicstaticbooleanisEmpty(Stringstr){returnstr==null||str.length()==0;}// 注意:没有 isBlank 方法!}
  • 4、检查是否有多个版本的 JAR?
    • 方法 A:列出所有 JAR 中的该类(需知道可能路径)
      # 查看 classpath 下所有 JARclassloader -l
    • 方法 B:搜索所有 ClassLoader 中的该类(Arthas 3.5+)
      # `-a` 表示 all classloaders,可发现不同 ClassLoader 加载了不同版本。sc -a *StringUtils*
    • 方法 C:查看某个 ClassLoader 加载了哪些资源
      # 先获取 ClassLoader hash(从 sc -d 输出中拿到,如 1c20c6b4)classloader -c 1c20c6b4 -r com/example/util/StringUtils.class# 输出:file:/app/lib/utils-1.0.jar!/com/example/util/StringUtils.class
  • 5、对比期望版本 vs 实际版本
    • 5.1. 将正确版本的StringUtils.class上传到服务器
    • 5.2. 用 Arthas 反编译对比:
      # 反编译线上加载的jad --source-only com.example.util.StringUtils>online.java# 反编译你本地正确的(先放到 /tmp/correct/ 目录)jad --source-only -c /tmp/correct/StringUtils.class>correct.java# diff 对比diffonline.java correct.java

总结:类加载问题排查流程图

Arthas 的sc+jad+classloader组合拳,是解决此类问题的“黄金三角”

graph TD A[出现 ClassNotFoundException / NoSuchMethodError] --> B{sc *ClassName* 是否有输出?} B -- 无 --> C[类未在 classpath,检查打包/依赖] B -- 有 --> D[sc -d ClassName 查看 code-source] D --> E[jad ClassName 确认方法/字段是否存在] E --> F{是否符合预期?} F -- 否 --> G[版本冲突!检查依赖树和 JAR 内容] F -- 是 --> H[检查 ClassLoader 是否隔离/重复加载] H --> I[classloader -a 或 sc -a 排查多加载]

使用实用建议

  • 1、精准监控特定参数
# 只监控用户名为 "admin" 的登录请求watchcom.example.service.UserService login'params[0]=="admin"'-v
  • 2、限制监控次数
# 只捕获前 3 次调用watchcom.example.service.UserService login'{params, returnObj}'-n3
  • 3、结合 OGNL 表达式过滤
watchcom.example.service.OrderService createOrder'params[0].amount > 1000'-x3
  • 4、快速定位 CPU 飙高
# 查看最耗 CPU 的线程thread -n3# 结合 jstack 分析死锁thread -b
  • 5、热修复(谨慎使用!)
# 1. 修改本地 .java 文件并编译成 .class# 2. 上传到服务器# 3. 执行redefine /tmp/UserService.class

注意:redefine不能增减字段/方法,仅支持方法体修改。

  • 6、导出堆快照(用于 MAT 或 JProfiler 分析内存泄漏。)
heapdump --live /tmp/heap.hprof
  • 7、类冲突定位:
    • 7.1、模糊搜索 + 包过滤(只搜自己项目的类,避免第三方干扰)sc com.yourcompany.*Service
    • 7.2、结合异常堆栈定位具体类(从异常日志中提取完整类名,直接sc -d它)
    • 7.3、注意内部类写法
      # 内部类要用 $ 分隔sc com.example.OuterClass$InnerClassjad com.example.OuterClass$InnerClass
    • 7.4、Spring Boot 特别注意
      • Spring Boot 使用LaunchedURLClassLoader
      • 类通常来自BOOT-INF/classesBOOT-INF/lib/xxx.jar
      • 如果sc -d显示code-source为空,可能是从classes目录加载(非 JAR)

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

Armbian网络配置终极指南:从零开始快速上手单板计算机联网

还在为你的单板计算机无法联网而烦恼吗&#xff1f;无论是Orange Pi、Raspberry Pi还是其他ARM设备&#xff0c;Armbian系统都提供了完整的网络解决方案。本指南将带你从基础配置到高级优化&#xff0c;让你轻松掌握嵌入式系统的联网技巧。 【免费下载链接】build Armbian Linu…

作者头像 李华
网站建设 2026/2/2 23:28:33

Zen Browser主题定制指南:打造属于你的专属浏览空间

Zen Browser主题定制指南&#xff1a;打造属于你的专属浏览空间 【免费下载链接】desktop &#x1f300; Experience tranquillity while browsing the web without people tracking you! 项目地址: https://gitcode.com/GitHub_Trending/desktop70/desktop 每天面对同样…

作者头像 李华
网站建设 2026/2/3 0:09:45

VinylMusicPlayer终极指南:打造完美的Android音乐播放体验

VinylMusicPlayer终极指南&#xff1a;打造完美的Android音乐播放体验 【免费下载链接】VinylMusicPlayer A material designed music player for Android 项目地址: https://gitcode.com/gh_mirrors/vi/VinylMusicPlayer VinylMusicPlayer是一款基于Material Design设计…

作者头像 李华
网站建设 2026/2/5 3:37:58

BongoCat虚拟桌面伴侣:三大官方模型深度解析与选择指南

BongoCat虚拟桌面伴侣&#xff1a;三大官方模型深度解析与选择指南 【免费下载链接】BongoCat 让呆萌可爱的 Bongo Cat 陪伴你的键盘敲击与鼠标操作&#xff0c;每一次输入都充满趣味与活力&#xff01; 项目地址: https://gitcode.com/gh_mirrors/bong/BongoCat 你是否…

作者头像 李华
网站建设 2026/2/11 9:51:51

3步解锁Qdrant混合搜索:告别语义搜索的尴尬时刻

3步解锁Qdrant混合搜索&#xff1a;告别语义搜索的尴尬时刻 【免费下载链接】qdrant Qdrant - 针对下一代人工智能的高性能、大规模向量数据库。同时提供云端版本 项目地址: https://gitcode.com/GitHub_Trending/qd/qdrant 你是否曾经遇到过这样的场景&#xff1a;用户…

作者头像 李华
网站建设 2026/2/11 6:08:05

零配置上手:x-spreadsheet在线表格的终极入门指南

零配置上手&#xff1a;x-spreadsheet在线表格的终极入门指南 【免费下载链接】x-spreadsheet The project has been migrated to wolf-table/table https://github.com/wolf-table/table 项目地址: https://gitcode.com/gh_mirrors/xs/x-spreadsheet 还在为网页集成电子…

作者头像 李华