一、Arthas核心原理
1. 动态字节码增强(核心机制)
- Instrumentation API:通过
java.lang.instrument挂载Agent - ByteBuddy框架:运行时修改字节码(替代ASM)
- 类重定义热更新:无需重启JVM实现代码注入
2. 架构分层
mermaidCopy Code
graph LR A[Client命令行] --> B[Telnet/HTTP协议] B --> C[Arthas Server] C --> D[JVMTI Agent] D --> E[目标JVM进程]
二、10大核心命令实战解析
1. dashboard - JVM全景监控
bashCopy Code
dashboard -i 2000 -n 5 # 每2秒刷新1次共5次
输出关键:
- 线程拓扑:死锁线程标红
- 内存分布:堆/非堆/GC次数
- 主机负载:CPU/内存实时占用
2. thread - 线程诊断
bashCopy Code
thread -b # 自动检测死锁 thread 108 # 查看指定ID线程栈 thread --state BLOCKED # 过滤阻塞线程
3. watch - 方法观测(生产调试利器)
bashCopy Code
watch com.example.UserService getUserById '{params, returnObj}' -x 3
参数解析:
params:方法入参returnObj:返回值-x 3:展开嵌套层级
4. trace - 调用链路追踪
bashCopy Code
trace -j com.xxx.Service *Order* '#cost>100' # 追踪耗时>100ms的Order相关方法
5. ognl - 动态执行代码(紧急修复神器)
bashCopy Code
ognl '@com.xxx.Config@getInstance().setSwitch(false)' # 关闭功能开关
6. redefine - 热更新.class文件
bashCopy Code
redefine /tmp/FixLoginService.class # 上传修复后的class文件
限制:不可修改方法签名/添加字段
7. profiler - 火焰图生成
bashCopy Code
profiler start # 启动采样 profiler stop --format html # 生成HTML火焰图
8. heapdump - 内存快照
bashCopy Code
heapdump /tmp/dump.hprof # 比jmap更安全的在线dump
9. logger - 日志级别热更新
bashCopy Code
logger --name ROOT --level debug # 动态调整Root Logger级别
10. vmtool - 内存对象操作
bashCopy Code
vmtool --action getInstances --className User --limit 10 # 获取内存中User对象
三、生产环境救火案例
场景1:CPU瞬时飙高
bashCopy Code
# 1. 快速定位热点线程 thread -n 3 -i 1000 # 2. 观测可疑方法参数 watch com.xxx.OrderService processOrder params -x 2 # 3. 确认是否为无效循环 trace com.xxx.util.* *Loop
场景2:内存泄漏定位
bashCopy Code
# 1. 检查对象增长 vmtool --action getInstances --className UserVO --limit 1000 # 2. 追踪创建路径 stack com.xxx.UserService createUser # 3. 导出堆分析 heapdump /tmp/oom.hprof
场景3:接口超时分析
bashCopy Code
# 1. 追踪慢请求链路 trace -j com.xxx.Gateway *route* '#cost>500' # 2. 检查下游调用 watch com.xxx.HttpClient execute 'throwExp' -e
四、高级技巧
1. 管道符组合命令
bashCopy Code
thread | grep 'http-nio' # 过滤Tomcat工作线程
2. 后台异步任务
bashCopy Code
trace -j com.xxx.Service *Async* > /tmp/trace.log & jobs # 查看后台任务
3. HTTP API远程调用
bashCopy Code
curl -XPOST http://127.0.0.1:8563/api -d 'command=watch com.xxx.* * {params}'
五、原理级注意事项
- 安全隔离:仅绑定
localhost避免暴露(启动参数--telnet-ip 127.0.0.1) - 字节码卸载:退出时自动清理增强类(通过
reset命令强制重置) - JDK兼容性:
- JDK 6+:基础功能支持
- JDK 8+:完整功能(推荐)
以下是某电商系统通过Arthas解决生产环境OOM问题的完整案例,包含真实场景的命令和输出:
案例背景
- 现象:订单服务凌晨3点触发
java.lang.OutOfMemoryError: Java heap space - 环境:JDK8,堆内存配置
-Xmx4G
1. 快速内存快照
bashCopy Code
[arthas@12345]$ heapdump /tmp/oom_heap.hprof -live Dumping heap to /tmp/oom_heap.hprof... Heap dump file created [3.7GB, 12s]
关键输出:文件大小接近堆上限,说明内存几乎耗尽
2. 分析大对象分布
bashCopy Code
[arthas@12345]$ vmtool --action getInstances --className java.util.HashMap --limit 1 @HashMap[][ @HashMap[ table=@Node[][ @Node[key=@String[user_123], value=@Order[...]], @Node[key=@String[user_456], value=@Order[...]], ... 50000+ elements ] ] ] Affect(row-cnt:1) cost in 235 ms
关键输出:发现一个HashMap持有5万+订单对象
3. 追踪对象引用链
bashCopy Code
[arthas@12345]$ ognl '@com.xxx.CacheHolder@userOrderCache' -x 2 @ConcurrentHashMap[ @String[global_cache]:@HashMap[size=50032], ... ]
关键输出:定位到静态变量CacheHolder.userOrderCache持续增长
4. 确认泄漏点
bashCopy Code
[arthas@12345]$ stack com.xxx.CacheHolder addOrder --cycle 10 Press Q or Ctrl+C to abort. Affect(class-cnt:1 , method-cnt:1) cost in 28 ms ts=2025-09-02 03:15:00;thread_name=pool-1-thread-3 @com.xxx.CacheHolder.addOrder() at com.xxx.OrderService.process(OrderService.java:112) at com.xxx.OrderController.create(OrderController.java:45)
关键输出:订单处理线程不断向静态缓存写入数据但无清理逻辑
5. 解决方案
修复代码:
javaCopy Code
// 原问题代码 public class CacheHolder { public static Map<String, Order> userOrderCache = new ConcurrentHashMap<>(); } // 修复后代码 public class CacheHolder { private static Map<String, Order> userOrderCache = new ConcurrentHashMap<>(); public static void addOrder(String userId, Order order) { userOrderCache.put(userId, order); // 添加LRU淘汰机制 if(userOrderCache.size() > 10000) { userOrderCache.remove(userOrderCache.keySet().iterator().next()); } } }
验证效果
bashCopy Code
[arthas@12345]$ vmtool --action getInstances --className java.util.HashMap --limit 1 @HashMap[][ @HashMap[size=9872] ] Affect(row-cnt:1) cost in 112 ms
修复后:缓存大小稳定在1万以内,OOM问题消失
根本原因
- 静态缓存
userOrderCache未设置上限 - 促销期间订单量激增导致缓存爆炸式增长
- 缓存对象被GC Roots强引用无法回收
以下是某金融系统通过Arthas解决生产环境CPU 100%问题的完整案例,包含真实命令和输出:
案例背景
- 现象:风控服务CPU持续100%,接口超时
- 环境:JDK11,4核8G容器
1. 定位高CPU线程
bashCopy Code
[arthas@67890]$ thread -n 3 -i 2000 Threads Top 3, interval=2000ms, cpuUsage=99.8% [1] risk-thread-pool-3 (Running, cpuUsage=92.7%) at com.xxx.RiskEngine.calculate(RiskEngine.java:155) at com.xxx.RiskEngine$$Lambda$45/0x00000008000b6840.run(Unknown Source) [2] risk-thread-pool-1 (Running, cpuUsage=5.1%) at com.xxx.RiskEngine.calculate(RiskEngine.java:148) [3] GC task thread#0 (ParallelGC, cpuUsage=1.2%) at jdk.internal.misc.Unsafe.park(Native Method)
关键输出:risk-thread-pool-3线程占用92.7% CPU,定位到RiskEngine.calculate方法
2. 生成火焰图
bashCopy Code
[arthas@67890]$ profiler start -d 30 -f /tmp/cpu_flame.svg Started [cpu] profiling for 30 seconds [arthas@67890]$ profiler stop profiler output file: /tmp/cpu_flame.svg [CPU flame graph]: 89% samples in com.xxx.RiskEngine.calculate
火焰图分析:89% CPU时间消耗在calculate方法中的正则匹配逻辑
3. 动态观察方法参数
bashCopy Code
[arthas@67890]$ watch com.xxx.RiskEngine calculate '{params,returnObj,throwExp}' '#cost>100' -x 3 -n 5 Press Q or Ctrl+C to abort. Affect(class-cnt:1 , method-cnt:1) cost in 53 ms ts=2025-09-02 10:30:00; cost=423ms; method=calculate params[0]=@RiskRequest[ rule="/^(a*)+$/", # ← 灾难性回溯正则 data="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!" ] returnObj=null throwExp=null
关键输出:发现输入数据触发正则/^(a*)+$/的灾难性回溯
4. 验证问题
bashCopy Code
[arthas@67890]$ ognl '@com.xxx.RiskEngine@PATTERN_CACHE' -x 1 @ConcurrentHashMap[ @String["default"]:Pattern.compile("/^(a*)+$/"), ... ]
输出确认:风险规则缓存了危险正则表达式
5. 解决方案
修复代码:
javaCopy Code
// 原问题代码 public class RiskEngine { private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>(); public static Pattern getPattern(String regex) { return PATTERN_CACHE.computeIfAbsent(regex, Pattern::compile); } } // 修复后代码 public class RiskEngine { private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>(); private static final int REGEX_COMPLEXITY_LIMIT = 20; // 新增复杂度限制 public static Pattern getPattern(String regex) { if (regex.length() > REGEX_COMPLEXITY_LIMIT) { throw new IllegalArgumentException("Regex too complex"); } return PATTERN_CACHE.computeIfAbsent(regex, Pattern::compile); } }
验证效果
bashCopy Code
[arthas@67890]$ thread -n 3 Threads Top 3, cpuUsage=45.3% [1] http-nio-8080-exec-1 (Running, cpuUsage=12.1%) at java.base@11.0.13/java.lang.Thread.sleep(Native Method) [2] risk-thread-pool-2 (Waiting, cpuUsage=8.7%) at jdk.internal.misc.Unsafe.park(Native Method) [3] GC task thread#0 (ParallelGC, cpuUsage=3.2%) at jdk.internal.misc.Unsafe.park(Native Method)
修复后:CPU使用率降至正常水平(<15%)
根本原因
- 危险正则表达式
/^(a*)+$/导致指数级回溯 - 风控规则引擎未对输入正则做复杂度校验
- 恶意构造的输入触发CPU爆满
1098

被折叠的 条评论
为什么被折叠?



