
你有没有遇到过这种场景线上服务突然CPU飙到90%日志里全是超时和异常但看不出到底卡在哪一行或者一个接口明明被频繁调用你想知道它内部哪一段最慢却只能靠猜又或者你怀疑线上运行的代码和本地版本不一致却没有办法直接验证。这些问题的共同特点是——你没法重启服务也没法停掉流量去调试。我这些年排查线上Java问题Arthas是少有的、能把这些玄学问题变成科学问题的工具甚至可以说没有Arthas之前很多线上问题我根本不敢碰。它不是通过改代码来加日志而是直接attach到正在运行的JVM上实时查看类加载、方法参数、返回值、耗时、异常堆栈甚至可以动态修改运行中的代码逻辑。这篇文章我就用自己真实的排查习惯把Arthas从下载、启动到常用命令、调优案例、生产注意事项完整过一遍适合所有Java后端开发和做系统运维的同行参考。1. 为什么常规手段搞不定线上问题Arthas 真正解决的是什么1.1 日志、监控和链路追踪的盲区大多数团队排查问题第一反应是去翻日志。但日志本身有几个致命弱点一是打点不全很多方法内部的关键参数根本没人记录二是日志有滞后性等你发现问题再去看可能已经被其他日志刷掉了三是日志撒谎因为打印日志本身有开销很多团队不会在循环里打日志导致你看到的现象只是局部现象。监控平台如Prometheus、Grafana能告诉你CPU、内存、RT这些指标在上涨但它是一个聚合视角只能让你知道出了事很难告诉你具体是哪行代码出的事。链路追踪如SkyWalking、Zipkin能定位到某个服务、某个接口慢但到了单机内部的某个方法尤其是没有埋点的方法它就无能为力了。更尴尬的场景是问题只出现在某个特定流量、特定参数下你无法用测试环境复现。你重新打包、重启、重新放流量可能问题就不再出现了但它并没有被解决只是被掩盖。这种时候你需要的是一个能钻进JVM内部的工具而不是在外部围观指标。1.2 Arthas 的思路给运行中的 JVM 装一个诊断仪表盘Arthas阿尔萨斯是阿里巴巴开源的Java诊断工具核心原理是利用Java的Instrumentation机制和目标JVM的Attach机制在不修改业务代码、不重启进程的前提下动态加载字节码增强逻辑。你可以把它想象成给一辆在高速公路上飞驰的车装上一个仪表盘不需要熄火、不需要拆发动机就能看到转速、油温、每个气缸的工作状态。它最打动我的地方是即插即用下载一个jar包启动后选择要attach的Java进程进入一个交互式命令行直接敲命令就能拿到结果。不需要提前在应用里引入Agent依赖也不需要重启服务。对于生产环境来说这个约束极其重要——因为你往往根本没有重启窗口。另外它在底层做了大量安全和控制工作比如通过字节码增强的类在Arthas退出后会还原不会污染线上代码比如命令执行有权限控制可以限制某些高危命令再比如对命令执行超时有处理机制防止诊断过程本身拖垮业务线程。这些细节让我在线上用它的时候心里比较有底。1.3 Arthas 适合谁来用、能解决哪些具体问题我接触过不少刚接触Arthas的同事他们最常问的问题是这玩意儿是不是只适合高手我的答案是只要你写过Java业务代码你就适合用。它不需要你精通JVM调优因为很多命令的语义非常直观——dashboard看全局、thread看线程、jad看反编译代码、watch看方法调用、trace看内部耗时。即便是初级开发用几条命令也能在一小时内上手。它具体能解决这些问题定位CPU飙高的线程和执行栈查看某个方法被谁调用、调用了多少次、平均耗时多少实时观察方法参数、返回值和抛出的异常反编译线上运行的类确认实际代码与本地是否一致在无法重启服务的情况下临时修改ClassName或方法实现热更新生成火焰图分析CPU热点和锁竞争。所以在本文后面的部分我会直接用一条条命令真实排障思路来讲不堆概念。2. 从下载到 attach 一个进程Arthas 的搭建与启动2.1 下载和启动的几种方式Arthas的安装非常简单本质上就是一个jar包。官方提供两种常用方式方式一直接下载arthas-boot.jar启动。curl -L https://arthas.aliyun.com/arthas-boot.jar -o arthas-boot.jar java -jar arthas-boot.jar推荐用阿里云的这个地址国内服务器下载速度快也稳定。如果下载太慢也可以去GitHub Releases页面找对应版本的arthas-bin.zip解压后运行./as.sh。方式二使用诊断脚本as.sh。下载下来的zip包解压后进入目录执行./as.sh它会自动扫描本机JVM进程然后让你选一个进行attach。启动后你会看到这样的输出[INFO] arthas-boot version: 3.7.1 [INFO] Found existing java process, please choose one and input the number: * [1]: 12345 com.example.dubboProvider [2]: 23456 org.apache.catalina.startup.Bootstrap输入序号或者直接指定PIDjava -jar arthas-boot.jar 12345attach成功后终端会显示Arthas的Logo并出现[arthas12345]$这样的交互提示符说明你已经进入了这个JVM实例。2.2 远程服务器上怎么用线上服务器一般不会给你直接登录到本机终端操作常见的方式是通过跳板机SSH登录再在远程终端里执行java -jar arthas-boot.jar。这种情况下要注意终端类型Arthas支持最基础的ANSI转义用普通的SSH会话即可不用额外配置X11或者Web界面。如果你有需求在本地电脑连接远程JVM可以使用Arthas Tunnel方式——远程部署tunnel-server在目标进程启动时注册本地通过Arthas Client连接。这个功能适合中大型团队做集中诊断但配置路径较长我建议个人排查先用SSH登录的方式简单直接。还有一个隐藏细节attach进程时Arthas会监听两个本地端口默认3658和8563。3658是用于telnet交互的端口8563是Http接口端口。如果服务器有防火墙且你需要从其他机器连接必须放行这两个端口但在同一台机器上SSH登录后使用就没有这个烦恼。我见过有人为了远程连接Arthas把这两端口裸跑到公网这非常危险——任何人都能通过telnet进入你的JVM并执行代码等于直接放开了一个大后门。2.3 attach失败和启动报错的常见原因我用Arthas这些年遇到过几次启动不顺利的情况归纳起来无非这几类权限不足Linux下如果当前用户不是Java进程的启动用户attach可能失败。解决方案是用sudo -u 启动用户 java -jar arthas-boot.jar或者切换到对应的系统账户再执行。JDK版本与Arthas版本不匹配老版本Arthas对Java 17、21的支持有坑尤其是Java 9的模块化系统对attach和Instrumentation有限制。遇到这种问题先把Arthas升级到最新版不要死磕旧版。端口被占用3658或8563被其他进程占用启动时会报bind exception。可以在启动命令中指定其他端口java -jar arthas-boot.jar --telnet-port 9999 --http-port 9998。应用本身自定义了类加载器某些极端框架比如OSGi容器对attach不友好必要时需要改在应用启动脚本中显式配置-javaagent参数。Java进程退出太快如果你attach的是那些一启动就退出的进程比如定时任务Arthas往往还没连上进程就没了。这种情况建议在申请内同时抓取启动日志或者改用-Darthas的agent方式随应用启动。记住Arthas本身不修改源码它在attach后对字节码的修改在退出执行stop或shutdown时会自动还原。所以不用太担心诊断过程给线上留下副作用。3. 高频命令逐个上桌这几条就够日常排查用了3.1 dashboard一屏看全局状态进入Arthas后我通常第一件事就是敲dashboard。这条命令会每5秒刷新一次展示当前JVM的线程快照、内存分区、GC统计、类加载数量和操作系统信息。$ dashboard ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON - main main 5 RUNNABLE 0.1 15.8 false false - DubboServerHandler-1 main 5 WAITING 0.0 3.2 false true ... Memory used total max usage heap 320M 512M 1024M 31.25% - eden 180M 256M 512M 35.15% - survivor 10M 10M 10M 100.00% - old 130M 246M 512M 25.39% - non-heap 95M ... GC - PS Scavenge count 120, time(ms) 3456 - PS MarkSweep count 5, time(ms) 1250实际输出字段会因JVM不同有些差异但核心语义不变。这个命令的价值是快速判断问题的宏观方向。比如我看到%CPU集中在某个线程下一步就该用thread抓那个线程的栈看到old区涨得很快且GC时间不断增长就该怀疑Full GC频率过高看到线程大量处于BLOCKED状态就该检查锁竞争。很多人一上来就追某个具体命令我的习惯是先看dashboard至少30秒让现象在眼里过一遍再决定下一步。dashboard有一个隐藏参数dashboard -i 1000指定刷新间隔为1000毫秒。生产环境建议把间隔调大一些比如3000毫秒减少诊断命令自身的资源占用。3.2 thread谁是CPU大户、谁在阻塞一抓一个准CPU飙高是线上最常见的故障Arthas的thread命令是定位元凶最强的手段。查看最繁忙的前3个线程thread -n 3这条命令会列出CPU占用最高的三个线程并打印每个线程的完整调用栈。你会直接看到某个线程卡在什么类的什么方法上那通常就是问题现场。采样模式下看最热线程thread -n 3 -i 1000这种模式会每1000毫秒采样一次返回过去一段时间内CPU使用率最高的线程。这样能避免瞬时波动带来的误导适合观察持续数分钟的CPU异常。找阻塞状态线程thread --state BLOCKED如果有线程被锁卡住这条命令能快速列出所有BLOCKED状态的线程再结合栈信息很容易判断是谁持锁不释放谁在等待。死锁的情况Arthas甚至会在输出里直接提示检测到死锁。实际使用中我遇到过不少线程看起来在RUNNABLE但CPU很高的情况。这时用thread -n 1看栈顶中的方法如果是java.util.HashMap的put方法或者自定义的循环逻辑基本可以断定是热点。如果是synchronized相关则需要再配合watch看锁对象。3.3 jad线上代码和本地不一样直接看反编译结果Java开发最怕一件事本地代码和我以为的线上代码不一致。可能是因为发布时没有构建最新的包可能是灰度只发到了一部分节点也可能是有人hot fix了但没同步版本。jad命令可以反编译线上加载的类jad com.example.OrderService输出非常像源码还标注了反编译来源和行号。如果看到的关键逻辑和本地不一致那问题就找到了——线上跑的根本不是你以为的那份代码。jad还有一种妙用配合watch去看某个私有方法的调用条件。比如你从class文件中看不到逻辑可以先jad反编译再根据行号去watch特定行思路会更清晰。需要注意jad输出的是反编译结果行号和原始源码可能对不上但它能反映实际的字节码逻辑。遇到极度混淆的代码反编译效果会打折扣但这种场景在业务系统中很少见。3.4 watch观察方法参数、返回值和异常治疑难杂症watch是我用的最频繁、也是被问得最多的命令。它能观测指定方法的入参、返回结果、调用耗时、抛出异常且有条件表达式能精准筛选你关心的调用。基础语法watch com.example.OrderService createOrder {params, returnObj, throwExp} #cost 100这个命令表示观测OrderService.createOrder方法当调用耗时#cost大于100ms时打印入参params、返回值returnObj和异常throwExp。观察表达式里常用的变量params所有参数的数组可以用params[0]取第一个参数也可以直接输出整个数组returnObj返回值对象如果方法返回void则为nullthrowExp抛出的异常target当前调用对象thisclazz当前类的Class对象method当前方法的反射对象#cost本次调用的耗时单位毫秒。只看前两个参数watch com.example.OrderService createOrder params[0], params[1] #cost 100只看异常调用watch com.example.OrderService createOrder throwExp #cost 100这个命令简直是我排查偶发性慢调用的利器。之前有个接口偶尔超时我通过watch加了参数和耗时条件等了十几分钟捕获到一次耗时500ms的调用发现参数里有个超大数组才定位到是序列化瓶颈。务必记得限制观测次数用-n 3表示只观测3次就自动结束否则高并发下watch的字节码增强会持续叠加性能开销。另外-x参数控制输出结果的展开层级遇到复杂对象打印成{...}时用-x 3加大展开深度。3.5 trace方法内部每条路径的耗时分布如果watch告诉你某个方法很慢下一步就是搞清楚慢在哪一段。trace命令能做到方法内部的精细耗时分析trace com.example.OrderService createOrder执行后每次调用createOrder都会输出类似这样的结果---ts2025-03-01 10:00:00thread_namehttp-nio-8080-exec-1id12is_daemontruepriority5 ---[100.123ms] com.example.OrderService1a2b3c4 createOrder() ---[60.123ms] com.example.PaymentService.pay() | ---[50.123ms] com.example.PaymentService.mockHttp() ---[30.123ms] com.example.OrderRepository.save() ---[5.123ms] com.example.AuditLog.record()从树状结构能直观看到整个方法耗时100ms其中PaymentService.pay()占了60ms而pay()内部又有一个HTTP调用占了50ms。这时候就可以快速判断喂慢在网络调用而不是数据库或业务逻辑。trace也支持条件和次数限制trace com.example.OrderService createOrder #cost 200 -n 5这个命令在生产环境要格外小心。因为它要增强方法内的字节码开销比watch更大。我建议只在两台机器的单台流量上执行或者只在低峰期用。你可以先看一下trace命令帮助中的--skipJDKMethod true选项跳过JDK类方法的追踪能减少不少噪音和开销。3.6 stack反向查询这个方法到底被谁调了有时候你发现一个方法被频繁执行但不知道它是从哪条调用链进来的。stack命令输入方法名就能列出当前所有调用该方法的调用栈。stack com.example.OrderService createOrder输出类似ts2025-03-01 10:00:00thread_namehttp-nio-8080-exec-3id11is_daemontruepriority5 ---[0.0ms] com.example.OrderController.createOrder() ---[0.0ms] com.example.OrderService.createOrder()它的常见用途有两个确认入口位置以及观察不同上游对同一方法的调用次数分布。如果你怀疑某个缓存预热任务和方法调用频率有关用stack非常直观。3.7 组合拳用这些命令串起一条完整排查链路单个命令能解决单点问题但真正头痛的问题是多个现象同时出现。我习惯把它们组合起来先dashboard看全局判断是CPU问题、内存问题还是线程问题再thread -n 3抓到具体线程和栈如果栈里指向某个方法就用jad确认线上代码逻辑如果你怀疑是该方法的参数或返回值导致用watch加上耗时条件抓现场最后用trace定位到具体内部路径。例如一次典型的慢接口排查我的命令顺序是dashboard→thread -n 3→jad→watch ... #cost 300→trace ... #cost 300。整个过程5-10分钟基本能把慢在哪一行问清楚。4. 动态改码和火焰图Arthas 的进阶玩法4.1 OGNL动态调用静态方法、访问字段灵活但需谨慎ognl命令可以让你在运行时执行Java表达式。它背后的OGNL表达式引擎非常强大可以访问对象的静态属性、调用方法、甚至构造对象。例如查看某个静态配置的值ognl com.example.ConfigUtilsMAX_RETRY或者调用静态方法ognl com.example.ServerManagergetServer()这在刚启动的系统里很实用——不用重启就能验证某些静态工具方法的逻辑。但它的危险程度也很高因为你可以通过OGNL执行任意代码相当于在线上开了一个代码后门。我强烈建议生产环境把ognl命令禁掉或者仅限具备授权的人员在低峰期使用。Arthas本身提供了--restrict参数可以禁止执行ognl、mc、redefine等高风险命令这个开关是个好东西。4.2 mcredefine热更新线上正在运行的类有些时候问题原因定位到了但临时解决方案不能让服务重启没有资源、没有窗口。Arthas提供了基于mcMemory Compiler和redefine命令的安全热更新能力。流程大概是这样的用sc查找目标类对应的类信息sc -d com.example.OrderServiceImpl用jad反编译当前类代码到本地文件或者直接写一个和原类同包名、同方法签名的.java文件jad --source-only com.example.OrderServiceImpl /tmp/OrderServiceImpl.java编辑Java文件修改有问题的逻辑。用mc编译修改后的文件mc /tmp/OrderServiceImpl.java -d /tmp/output用redefine加载编译好的class文件redefine /tmp/output/OrderServiceImpl.class执行成功后线上这个类的方法实现就变了不需要重启。但是这里有几个非常容易踩的坑redefine不能增加、删除或修改字段也不能修改方法签名只能改方法实现体。因为它本质上是替换方法字节码类的结构必须保持一致。Arthas自己的watch/trace增强和redefine叠加时可能冲突。一般来说先redefine再watch没问题但如果你已经watch了某个方法又去redefine有可能导致增强丢失或逻辑异常。建议redefine前先执行stop或清除已有增强。热更新不能解决类静态初始化已经完成的问题——如果问题出在static块里redefine不会重新执行static逻辑。redefine对Lambda表达式和内部类支持也有限制我在一个用lambda写的回调类上redefine过一调就报错后来改成匿名内部类才正常。热更新是双刃剑我在生产环境用它不超过三次每次都提心吊胆。如果你只是临时绕过一段逻辑可以用更简单的方式比如通过watch的#cost条件先确认问题然后找到一个临时配置开关来切换逻辑而不是直接改字节码。热更新适合实在没有其他选择的时刻。4.3 profiler火焰图定位CPU热点和锁竞争Arthas内置了基于async-profiler的profiler命令可以生成火焰图Flame Graph。这是我在做JVM调优时最依赖的功能之一。基本用法profiler start # 等待1~3分钟期间让请求正常跑或者对目标场景压测 profiler stop --format html --file /tmp/flamegraph.html生成之后用浏览器打开HTML文件你会看到一副像火焰一样的图。底部是调用栈的入口顶部是叶子方法。哪个方法在图上占的面积最大就是CPU耗时热点。火焰图中出现一段很宽的平顶说明某个方法处有大量计算或循环出现尖刺则多半是频繁GC或短小的热点调用。如果你要观察JVM自身的方法调用比如GC线程、内存分配可以用profiler start --event alloc这会采样分配事件定位哪些对象占用了大量内存。有一点要说明profiler start默认采样CPU事件采样频率较高对业务会有少量干扰。建议在需要定位明确问题时先观察线程栈确认方向后再做一次不超过3分钟的profiler采样而不是让profiler长时间开着。火焰图文件的解析也需要一点经验。我第一次看到满屏的ThreadPoolExecutor.getTask时以为线程池有问题后来才明白那是线程空闲等待的常见模样。所以看火焰图时先把线程池、JIT编译、安全点这些基础设施过滤掉再聚焦到业务方法的调用栈上这样才不容易被骗。4.4 如何把Arthas变成团队可用的小工具实际工作中团队成员水平参差如果在生产环境让每个人都直接敲Arthas命令风险太高。我建议可以做两件事一是把常用命令固化为脚本。Arthas支持-c参数执行单条命令java -jar arthas-boot.jar 12345 -c dashboard -i 2000也可以写成一个脚本文件通过-f执行java -jar arthas-boot.jar 12345 -f /tmp/diagnose.as脚本里每行一条命令执行完自动退出。这样既避免了人工输入的高错误率又能把整个诊断过程固化成可重复执行的排障SOP。二是限制高危命令。在启动Arthas时加上--restrict可以禁止执行有修改能力的命令比如redefine、mc、ognl只保留只读诊断命令。对于只做监控和第一天排查用途的账号这个限制极其必要。5. 一次真实CPU飙高事故的完整复盘我是怎么5分钟定位到问题的5.1 现象描述有一次线上一个核心订单服务在高峰期突然CPU使用率飙升到95%以上接口RT从50ms涨到1200ms用户开始出现明显的卡顿和超时。监控平台告警是CPU使用率超过80%持续5分钟但给不出更多线索。如果是以前我可能第一反应是重启大法。但重启之后问题是否还会回来未知。所以那次我坚持用Arthas排查到底。5.2 排查链路从dashboard到线程栈我通过SSH登录到出问题的节点执行java -jar arthas-boot.jar选择那个服务进程进入Arthas。第一步dashboard看全局。输出里CPU列显示大量线程都很忙但GC时间并不长内存用量也正常。这排除了Full GC导致CPU飙升的可能性问题大概率出在业务代码或者某个无限循环上。第二步thread -n 3抓最忙线程。命令执行后我看到了类似这样的栈信息http-nio-8080-exec-12 Id34 RUNNABLE at java.util.LinkedList.pollFirst(LinkedList.java:540) at com.example.OrderQueue.take(OrderQueue.java:78) at com.example.MainLoop.run(MainLoop.java:23)多个线程都卡在这个OrderQueue.take上很像一个忙等的实现——栈上是pollFirst而不是take()等待。这就是典型的忙等循环线程一直在空转拿不到数据导致CPU被白白消耗。第三步jad反编译确认逻辑。我执行jad com.example.MainLoop反编译后发现while循环里对队列判空时使用了peek()Thread.sleep(1)的组合但由于某些时期队列一直为空1ms的sleep唤醒后马上又空转多个线程叠加起来CPU自然就飙了。第四步watch验证。我用watch观察OrderQueue.take方法的入参和返回值加了#cost 10的条件确认慢调用发生时的队列长度始终为0进一步证实是空闲忙等而非业务阻塞。到这里问题的根因已经很明确一个不合理的忙等循环设计它在低流量时段让多个线程持续空转消耗了大量CPU进而拖慢整个JVM的响应。5.3 解决方案和后续验证我随后做了两件事通过配置中心热更新把OrderQueue.take的逻辑改为用Object.wait()/notifyAll()或者利用条件变量阻塞等待避免忙等。在等待队列为空时不触发redefine而是让代码修复版本走正常发布流程因为业务高峰期处理风险太大。在发布之前我仍然用Arthas持续观察了几分钟执行dashboard -i 5000确认CPU从95%降到了25%执行thread -n 3确认最忙线程栈不再是空转逻辑。整个过程从进入Arthas到定位问题大约5分钟真正改代码发布那是后面的事。这次复盘给我最深的感受是Arthas不是用来搞玄学的它的价值在于把猜测变成验证。没有它这个问题我大概率只能靠重启缓解然后等着下次再爆。6. 生产环境用 Arthas 的忠告有些坑我真的踩过6.1 权限和审计能执行命令的地方就是后门Arthas的能力范围很大尤其是ognl和redefine直接等同于在运行中的JVM里执行任意代码。所以生产环境部署Arthas第一原则就是权限最小化。我建议Arthas所在的服务器只允许运维或者指定负责人通过堡垒机登录不要给所有开发同事开放root或服务账号尽量使用--restrict模式运行Arthas禁止修改类、禁止执行ognl表达式只保留只读诊断命令不要对外裸露arthas的telnet和http端口即使是内网也要通过跳板或隧道访问如果团队规模较大搭建Arthas Tunnel Server并加认证授权把访问统一收敛到管理平台。在某家公司我见过一次事故一个开发为了看线上类把Arthas的telnet端口映射到了公网结果当天夜里就被扫描到被人用ognl执行了一段卸载类的命令虽然后面恢复了但那种冲击感让我一直把安全边界放在第一位。6.2 性能开销watch/trace 是放大镜也是放大麻烦任何诊断命令都有运行时开销Arthas也不例外。普通dashboard开销很小但watch和trace会对目标方法进行字节码增强每调用一次都要计算表达式、收集上下文在高并发方法上放大会非常吓人。我踩过一个实实在在的坑对一个日调用量上亿的方法用watch且没加-n限制结果每分钟额外产生了几千条增强指令的耗时接口RT瞬间多了几十毫秒差点把服务打挂。正确的姿势务必加-n限制观察次数比如-n 3只看三次务必用条件表达式过滤比如#cost 200或者params[0].userId 特定值减少无效观察尽量在低峰期使用用单台节点验证不要全量操作trace命令层级不要开太深必要时用--skipJDKMethod true跳过JDK方法减少噪音和开销用完后及时执行stop或退出Arthas清理字节码增强。6.3 JVM版本适配和Arthas版本管理Arthas本身更新频率不慢但很多公司用的是老版本遇到JDK版本升级就容易踩坑。比如在Java 8上跑得好好的Arthas 3.4.x到Java 17上可能attach不上或者命令输出异常。我的习惯是长期维护一个固定版本号和JDK版本的对照表确保新引入的JDK版本匹配的Arthas版本是验证过的每次升级JDK先在一台测试机上跑一遍Arthas核心命令而不是等到线上故障才发现不能用关注Arthas官方Release Note遇到JDK兼容性修复及时升级。这里也提醒一下Java 9引入了模块化系统Arthas在attach时可能需要额外的--add-opens参数具体取决于你的应用启动参数。如果一个应用用了非常严的模块限制Arthas有可能会诊断失败这是环境限制而不是Arthas bug。6.4 打造个人排障套路把Arthas变成肌肉记忆工具再好平时不用真到故障时候还是会手忙脚乱。我建议任何时候都要做两件简单的事一是平时在压力测试环境或者灰度环境刻意用Arthas去视察系统状态。不要说等出了事再学——生产事故往往发生在凌晨三点那时候你没有时间去翻帮助文档。提前练过几条命令哪怕只是看dashboard和thread都会让你在紧张时刻稳定很多。二是给自己维护一个命令速查表。不需要多复杂A4纸打印出来贴电脑旁也行。内容就写清楚每个命令的语法意图比如场景命令全局一眼看状态dashboard -i 2000找最忙线程thread -n 3找阻塞线程thread --state BLOCKED反编译线上类jad com.example.MyService观察慢调用watch com.example.MyService method #cost 100 -n 3看内部耗时trace com.example.MyService method #cost 100 -n 3生成火焰图profiler start然后profiler stop --format html --file /tmp/fg.html这张表让我在跨团队帮别人排障时也能快速给出统一的标准操作而不会被临时问一句Arthas怎么用就乱了阵脚。从几年前第一次听说Arthas到如今把它当作排障工具箱里的标配我对它的评价是它不是万能的但在绝大多数线上Java问题不能停、不能重启、不能改代码的约束下它几乎是唯一可行的实时诊断手段。如果你还没有在生产环境里试过它我的建议很直接下次遇到一个慢接口或者CPU波动别急着重启先试着用Arthas抓一次现场。你可能第一次不熟练但用上三条命令以后你大概就能体会它为什么配得上Java诊断利器这个名号。