Java开发工具——Arthas线上查询工具

article/2025/6/26 12:21:52

摘要

本文主要介绍了 Java 开发工具 Arthas 的安装、启动及使用。包括本地安装与启动、容器安装与启动、基础命令与使用以及常用命令与使用等内容。通过 Arthas,开发者可以方便地对 Java 应用进行线上排错和监控,提高开发效率。

1. Arthas 本地安装与启动

1.1. Arthas的安装

📎arthas-boot.jar

# 下载Arthas工具包
curl -O https://arthas.aliyun.com/arthas-boot.jar# 启动Arthas服务
java -jar arthas-boot.jar

1.2. Arthas 插件下载

2. Arthas 容器安装与启动

很多时候,应用在 docker 里出现 arthas 无法工作的问题,是因为应用没有安装 JDK ,而是安装了 JRE 。如果只安装了 JRE,则会缺少很多 JAVA 的命令行工具和类库,Arthas 也没办法正常工作。下面介绍两种常见的在 Docker 里使用 JDK 的方式。

2.1. 通过包管理软件来安装

Arthas安装到基础镜像

FROM openjdk:8-jdk-alpine# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
# Install OpenJDK-8
RUN apt-get update && \apt-get install -y openjdk-8-jdk && \apt-get install -y ant && \apt-get clean;# Fix certificate issues
RUN apt-get update && \apt-get install ca-certificates-java && \apt-get clean && \update-ca-certificates -f;# Setup JAVA_HOME -- useful for docker commandline
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
RUN export JAVA_HOME

或者使用

RUN yum install -y \java-1.8.0-openjdk \java-1.8.0-openjdk-develENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/
RUN export JAVA_HOME

2.2. 诊断Docker里的Java进程(服务器联网状态)

# 使用Arthas诊断docker 容器服务
docker exec -it  ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"

2.3. Docker对应服务器无法联网联网

2.3.1. 本地下载 arthas-boot.jar

wget https://arthas.aliyun.com/arthas-boot.jar

2.3.2. 复制文件到容器

docker cp arthas-boot.jar <container_id>:/tmp/arthas-boot.jar

2.3.3. 登录容器执行 Arthas

docker exec -it <container_id> /bin/bashjava -jar /tmp/arthas-boot.jar

接下来根据提示选择 Java 进程即可 attach。

2.4. 诊断k8s里容器里的Java进程(服务器联网状态)

kubectl exec -it ${pod} --container ${containerId} -- /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"

2.5. k8s 对应服务器无法联网联网

2.5.1. 下载 arthas-boot.jar 到本地

wget https://arthas.aliyun.com/arthas-boot.jar

2.5.2. 拷贝到 Pod 中(支持压缩传输)

kubectl cp arthas-boot.jar <namespace>/<pod>:/tmp/arthas-boot.jar -c <container_name>

2.5.3. 登录 Pod 并执行 Arthas

kubectl exec -it <pod> -c <container_name> -- /bin/shjava -jar /tmp/arthas-boot.jar

3. Arthas 远程登录与连接

3.1. Arthas Web Console登录

http://IP:8563/

3.2. Arthas Tunnel Server集群管理

通过 Arthas Tunnel Server/Client 来远程管理/连接多个 Agent。比如,在流式计算里,Java 进程可以是在不同的机器启动的,想要使用 Arthas 去诊断会比较麻烦,因为用户通常没有机器的权限,即使登陆机器也分不清是哪个 Java 进程。在这种情况下,可以使用 Arthas Tunnel Server/Client。

3.2.1. 下载Arthas Tunnel Server (https://github.com/alibaba/arthas/releases)

3.2.2. 启动 arthas 时连接到 tunnel server

在启动 arthas,可以传递--tunnel-server参数,attach 成功之后,会打印出 agentId,比如:

as.sh --tunnel-server 'ws://127.0.0.1:7777/ws'
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---./  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'wiki      https://arthas.aliyun.com/doc
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
version   3.1.2
pid       86183
time      2019-08-30 15:40:53
id        URJZ5L48RPBR2ALI5K4V

如果是启动时没有连接到 tunnel server,也可以在后续自动重连成功之后,通过 session 命令来获取 agentId:

[arthas@86183]$ sessionName           Value
-----------------------------------------------------JAVA_PID       86183SESSION_ID     f7273eb5-e7b0-4a00-bc5b-3fe55d741882AGENT_ID       URJZ5L48RPBR2ALI5K4VTUNNEL_SERVER  ws://47.75.156.201:80/ws

4. Arthas 基础命令与使用

4.1. dashboard(查询进程所有信息)

实时展示 Java 应用当前线程、内存、GC、运行环境等关键指标,是 Arthas 最常用的系统监控入口命令。

$ dashboard
ID     NAME                   GROUP          PRIORI STATE  %CPU    TIME   INTERRU DAEMON
17     pool-2-thread-1        system         5      WAITIN 67      0:0    false   false
27     Timer-for-arthas-dashb system         10     RUNNAB 32      0:0    false   true
11     AsyncAppender-Worker-a system         9      WAITIN 0       0:0    false   true
9      Attach Listener        system         9      RUNNAB 0       0:0    false   true
3      Finalizer              system         8      WAITIN 0       0:0    false   true
2      Reference Handler      system         10     WAITIN 0       0:0    false   true
4      Signal Dispatcher      system         9      RUNNAB 0       0:0    false   true
26     as-command-execute-dae system         10     TIMED_ 0       0:0    false   true
13     job-timeout            system         9      TIMED_ 0       0:0    false   true
1      main                   main           5      TIMED_ 0       0:0    false   false
14     nioEventLoopGroup-2-1  system         10     RUNNAB 0       0:0    false   false
18     nioEventLoopGroup-2-2  system         10     RUNNAB 0       0:0    false   false
23     nioEventLoopGroup-2-3  system         10     RUNNAB 0       0:0    false   false
15     nioEventLoopGroup-3-1  system         10     RUNNAB 0       0:0    false   false

ID

NAME

GROUP

PRIORI

STATE

%CPU

TIME

INTERRUPT

DAEMON

线程 ID,系统唯一标识

线程名称(如 nioEventLoop、main 等)

所属线程组(如 system、main)

线程优先级(默认 5,一般很少调整)

当前线程状态,如 WAITING、RUNNABLE、TIMED_WAITING 等

当前线程的 CPU 占用百分比(最近时间片)

线程运行的总时间(从 JVM 启动开始计算)

线程是否被中断(true/false)

是否是守护线程(true 表示后台线程,不会阻止 JVM 退出)

Memory             used   total max    usage GC
heap               32M    155M  1820M  1.77% gc.ps_scavenge.count  4
ps_eden_space      14M    65M   672M   2.21% gc.ps_scavenge.time(m 166
ps_survivor_space  4M     5M    5M           s)
ps_old_gen         12M    85M   1365M  0.91% gc.ps_marksweep.count 0
nonheap            20M    23M   -1           gc.ps_marksweep.time( 0
code_cache         3M     5M    240M   1.32% ms)

heap

ps_eden_space

ps_survivor_space

ps_old_gen

nonheap

code_cache

Java 堆使用情况(主要存储对象)

年轻代 Eden 区

年轻代 Survivor 区

老年代,长期存活对象

非堆区(类元数据、方法区、常量池等)

JIT 编译生成的机器代码缓存

注意:ps_* 是 Parallel Scavenge 垃圾回收器的标志(说明当前 JVM 使用的是 PS GC),

Java堆 = Eden区 + Survivor区(S0 + S1)+ 老年代

gc.ps_scavenge.count

gc.ps_scavenge.time

gc.ps_marksweep.count

gc.ps_marksweep.time

PS 新生代垃圾收集次数

PS 新生代 GC 总耗时(毫秒)

老年代 GC 次数

老年代 GC 总耗时

说明:

  • 新生代 GC 发生了 4 次,总共耗时 166 毫秒
  • 老年代未发生 GC,说明内存压力不大

4.2. thread (查询进程信息)

参数名称

参数说明

id

线程 id

[n:]

指定最忙的前 N 个线程并打印堆栈

[b]

找出当前阻塞其他线程的线程

[i <value>

]

指定 cpu 使用率统计的采样间隔,单位为毫秒,默认值为 200

[--all]

显示所有匹配的线程

查看当前线程信息,查看线程的堆栈。这里的 cpu 使用率与 linux 命令top -H -p <pid> 的线程%CPU类似,一段采样间隔时间内,当前 JVM 里各个线程的增量 cpu 时间与采样间隔时间的比例。

$ thread 1 | grep 'main('at demo.MathGame.main(MathGame.java:17)

4.2.1. thread id, 显示指定线程的运行堆栈

[arthas@22888]$ thread 24
"xxl-job, admin JobScheduleHelper#scheduleThread" Id=24 TIMED_WAITINGat java.lang.Thread.sleep(Native Method)at java.lang.Thread.sleep(Thread.java:342)at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)at com.xxl.job.admin.core.thread.JobScheduleHelper$1.run(JobScheduleHelper.java:202)at java.lang.Thread.run(Thread.java:750)

行号

内容

含义

1

"xxl-job, admin JobScheduleHelper#scheduleThread"

这是线程的名字,表明该线程是 xxl-job 调度器里的 scheduleThread(调度线程)

2

Id=24 TIMED_WAITING

线程 ID 是 24,当前状态是 TIMED_WAITING,表示它在“等待一段时间”

3

at java.lang.Thread.sleep(Native Method)

线程正在执行 Thread.sleep(),是阻塞等待的一种方式

4-6

逐级调用栈信息:显示线程是怎么运行到当前这一步的

TimeUnit.sleep()JobScheduleHelper.run()进入休眠

6

at com.xxl.job.admin.core.thread.JobScheduleHelper$1.run(JobScheduleHelper.java:202)

这是你关心的业务代码部分,调度线程当前在 JobScheduleHelper类中第 202 行

7

at java.lang.Thread.run(Thread.java:750)

线程入口是 Thread.run()方法

这说明:

  • 这个线程是 XXL-JOB 的调度线程,名字为:JobScheduleHelper#scheduleThread
  • 当前处于 TIMED_WAITING 状态,即线程执行了 Thread.sleep()正在等待下一次调度周期到来
  • 它没有卡死、也没有异常,只是在正常等待
  • 属于预期行为(定时任务调度器大多使用 sleep/wait 控制节奏)

4.2.2. thread -b, 找出当前阻塞其他线程的线程:

thread -b  (查询阻塞线程)
$ thread -b
"http-bio-8080-exec-4" Id=27 TIMED_WAITINGat java.lang.Thread.sleep(Native Method)at test.arthas.TestThreadBlocking.doGet(TestThreadBlocking.java:22)-  locked java.lang.Object@725be470 <---- but blocks 4 other threads!at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)at test.filter.TestDurexFilter.doFilter(TestDurexFilter.java:46)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)at com.taobao.tomcat.valves.ContextLoadFilterValve$FilterChainAdapter.doFilter(ContextLoadFilterValve.java:191)at com.taobao.eagleeye.EagleEyeFilter.doFilter(EagleEyeFilter.java:81)at com.taobao.tomcat.valves.ContextLoadFilterValve.invoke(ContextLoadFilterValve.java:150)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:429)at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)-  locked org.apache.tomcat.util.net.SocketWrapper@7127ee12at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:745)Number of locked synchronizers = 1- java.util.concurrent.ThreadPoolExecutor$Worker@31a6493e

4.2.3. 支持一键展示当前最忙的前 N 个线程并打印堆栈:

[arthas@22888]$ thread -n 2
"C1 CompilerThread2" [Internal] cpuUsage=0.36% deltaTime=0ms time=14085ms"arthas-command-execute" Id=19733 cpuUsage=0.17% deltaTime=0ms time=16ms RUNNABLEat sun.management.ThreadImpl.dumpThreads0(Native Method)at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:750)

4.3. jad (反编译代码)

jad 包名 类示例:
jad --source-only com.zhuangxiaoyan.hyxftest.bridge.UrgentMessageStrategy send
$ jad demo.MathGame(ClassLoader:
+-sun.misc.Launcher$AppClassLoader@3d4eac69
+-sun.misc.Launcher$ExtClassLoader@66350f69Location:
/tmp/math-game.jar/** Decompiled with CFR 0_132.*/
package demo;import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;public class MathGame {private static Random random = new Random();private int illegalArgumentCount = 0;public static void main(String[] args) throws InterruptedException {MathGame game = new MathGame();do {game.run();TimeUnit.SECONDS.sleep(1L);} while (true);}public void run() throws InterruptedException {try {int number = random.nextInt();List<Integer> primeFactors = this.primeFactors(number);MathGame.print(number, primeFactors);}catch (Exception e) {System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());}}public static void print(int number, List<Integer> primeFactors) {StringBuffer sb = new StringBuffer("" + number + "=");Iterator<Integer> iterator = primeFactors.iterator();while (iterator.hasNext()) {int factor = iterator.next();sb.append(factor).append('*');}if (sb.charAt(sb.length() - 1) == '*') {sb.deleteCharAt(sb.length() - 1);}System.out.println(sb);}public List<Integer> primeFactors(int number) {if (number < 2) {++this.illegalArgumentCount;throw new IllegalArgumentException("number is: " + number + ", need >= 2");}ArrayList<Integer> result = new ArrayList<Integer>();int i = 2;while (i <= number) {if (number % i == 0) {result.add(i);number /= i;i = 2;continue;}++i;}return result;}
}Affect(row-cnt:1) cost in 970 ms.

4.4. watch(查询函数调用输入输出)

同时看入参和返回值,也可以这样:

watch 包名 函数名 '{params,returnObj,throwExp}'  -n 5  -x 3 示例:
watch com.zhuangxiaoyan.hyxftest.bridge.UrgentMessageStrategy send '{params,returnObj,throwExp}'  -n 5  -x 3 

通过watch命令来查看demo.MathGame#primeFactors函数的返回值:

$ watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 46 ms.
ts=2018-12-03 19:29:54; [cost=0.01696ms] result=@ArrayList[@Object[][@Integer[1],],@MathGame[random=@Random[java.util.Random@522b408a],illegalArgumentCount=@Integer[13038],],null,
]
ts=2018-12-03 19:29:54; [cost=4.277392ms] result=@ArrayList[@Object[][@Integer[1],],@MathGame[random=@Random[java.util.Random@522b408a],illegalArgumentCount=@Integer[13038],],@ArrayList[@Integer[2],@Integer[2],@Integer[2],@Integer[5],@Integer[5],@Integer[73],@Integer[241],@Integer[439],],
]
  • watch 命令定义了 4 个观察事件点,即 -b 函数调用前,-e 函数异常后,-s 函数返回后,-f 函数结束后
  • 4 个观察事件点 -b-e-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
  • 这里要注意函数入参函数出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表函数入参外,其余事件都代表函数出参
  • 当使用 -b 时,由于观察事件点是在函数调用前,此时返回值或异常均不存在
  • 在 watch 命令的结果里,会打印出location信息。location有三种可能值:AtEnterAtExitAtExceptionExit。对应函数入口,函数正常 return,函数抛出异常。

4.5. arthas (服务退出与关闭)

// 服务关闭
quitexit

如果只是退出当前的连接,可以用quit或者exit命令。Attach 到目标进程上的 arthas 还会继续运行,端口会保持开放,下次连接时可以直接连接上。

// 服务退出
stop

如果想完全退出 arthas,可以执行stop命令。

5. Arthas 常用命令与使用

5.1. getstatic 查询类的静态属性

# 使用方法为getstatic class_name field_name$ getstatic demo.MathGame random
field: random
@Random[serialVersionUID=@Long[3905348978240129619],seed=@AtomicLong[120955813885284],multiplier=@Long[25214903917],addend=@Long[11],mask=@Long[281474976710655],DOUBLE_UNIT=@Double[1.1102230246251565E-16],BadBound=@String[bound must be positive],BadRange=@String[bound must be greater than origin],BadSize=@String[size must be non-negative],seedUniquifier=@AtomicLong[-3282039941672302964],nextNextGaussian=@Double[0.0],haveNextNextGaussian=@Boolean[false],serialPersistentFields=@ObjectStreamField[][isEmpty=false;size=3],unsafe=@Unsafe[sun.misc.Unsafe@2eaa1027],seedOffset=@Long[24],
]

5.2. monitor(方法执行监控)

monitor 包名 函数名  -n 10  --cycle 10 monitor com.zhuangxiaoyan.hyxftest.bridge.UrgentMessageStrategy send  -n 10  --cycle 10 

对匹配 class-patternmethod-patterncondition-express的类、方法的调用进行监控。monitor 命令是一个非实时返回命令. 实时返回命令是输入之后立即返回,而非实时返回的命令,则是不断的等待目标 Java 进程返回信息,直到用户输入 Ctrl+C 为止。

服务端是以任务的形式在后台跑任务,植入的代码随着任务的中止而不会被执行,所以任务关闭后,不会对原有性能产生太大影响,而且原则上,任何 Arthas 命令不会引起原有业务逻辑的改变。

监控项

说明

timestamp

时间戳

class

Java 类

method

方法(构造方法、普通方法)

total

调用次数

success

成功次数

fail

失败次数

rt

平均 RT

fail-rate

失败率

参数名称

参数说明

class-pattern

类名表达式匹配

method-pattern

方法名表达式匹配

condition-express

条件表达式

[E]

开启正则表达式匹配,默认为通配符匹配

[c:]

统计周期,默认值为 120 秒

[b]

方法调用之前计算 condition-express

[m <arg>]

指定 Class 最大匹配数量,默认值为 50。长格式为[maxMatch <arg>]

$ monitor -c 5 demo.MathGame primeFactors
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:38  demo.MathGame  primeFactors  5      1        4     1.15        80.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:43  demo.MathGame  primeFactors  5      3        2     42.29       40.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:48  demo.MathGame  primeFactors  5      3        2     67.92       40.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:53  demo.MathGame  primeFactors  5      2        3     0.25        60.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:58  demo.MathGame  primeFactors  1      1        0     0.45        0.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:07:03  demo.MathGame  primeFactors  2      2        0     3182.72     0.00%

5.3. retransform(动态热加载新的文件)

类,类加载相关的命令

说明

sc

Search Class 查看运行中的类信息

sm

Search Method 查看类中方法的信息

jad

反编译字节码为源代码

mc

Memory Compile 将源代码编译成字节码

redefine

将编译好的字节码文件加载到jvm中运行

5.3.1.1. 下载jar 包

下载demo-arthas-spring-boot.jar(https://github.com/hengyunabc/spring-boot-inside/blob/master/demo-arthas-spring-boot/demo-arthas-spring-boot.jar),再用java -jar命令启动:

# 访问接口
curl http://localhost:80/user/0# 返回结果
{"timestamp":1550223186170,"status":500,"error":"Internal Server Error","exception":"java.lang.IllegalArgumentException","message":"id < 1","path":"/user/0"}
5.3.1.2. Arthas使用jad反编译UserController
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
# 修改UserController文件
vim /tmp/UserController.java# 文件如下
@GetMapping(value={"/user/{id}"})
public User findUserById(@PathVariable Integer id) {logger.info("retransform test id: {}", (Object)id);if (id != null && id < 1) {return new User(id, "retransform  name" + id);// throw new IllegalArgumentException("id < 1");}return new User(id.intValue(), "name" + id);
}
5.3.1.3. Arthas中使用sc查找加载UserController的ClassLoader
# sc 命令
sc -d *UserController | grep classLoaderHash# sc 命令结果
$ sc -d *UserController | grep classLoaderHashclassLoaderHash   1be6f5c3

可以发现是 spring boot LaunchedURLClassLoader@1be6f5c3 加载的。

注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。

如果你使用-c,你需要手动输入hashcode:-c <hashcode>

对于只有唯一实例的ClassLoader可以通过--classLoaderClass指定class name,使用起来更加方便.

--classLoaderClass 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而-c <hashcode>是动态变化的。

5.3.1.4. Athas中使用mc 编译修改后的文件

保存好/tmp/UserController.java之后,使用mc(Memory Compiler)命令来编译,并且通过--classLoaderClass参数指定ClassLoader:

# mc 编译修改的新的文件
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp# 命令结果如下:
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
5.3.1.5. retransform加载新class 文件
# retransform 命令
retransform /tmp/com/example/demo/arthas/user/UserController.class# retransform 命令结果如下:
$ retransform /tmp/com/example/demo/arthas/user/UserController.class
retransform success, size: 1
5.3.1.6. 重新访问:

5.4. reset (重置增强类)

重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端stop时会重置所有增强过的类。

$ trace Test test
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 57 ms.
`---ts=2017-10-26 17:10:33;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@14dad5dc`---[0.590102ms] Test:test()`---ts=2017-10-26 17:10:34;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@14dad5dc`---[0.068692ms] Test:test()$ reset Test
Affect(class-cnt:1 , method-cnt:0) cost in 11 ms.
$ trace Test test
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 15 ms.
`---ts=2017-10-26 17:12:06;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@14dad5dc`---[0.128518ms] Test:test()# 还原所有类
$ reset
Affect(class-cnt:1 , method-cnt:0) cost in 9 ms.

博文参考

  • https://github.com/alibaba/arthas/blob/master/math-game/src/main/java/demo/MathGame.java
  • Arthas Tunnel | arthas
  • 简介 | arthas

http://www.hkcw.cn/article/YWrUfHeBPe.shtml

相关文章

5.RV1126-OPENCV 图形计算面积

一.图形面积、弧长计算介绍 前面我们已经把图形轮廓的检测、画框等功能讲解了一遍。这次主要结合轮廓检测的 API 去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的 API 如 contourArea…

rabbitmq Topic交换机简介

1. Topic交换机 说明 尽管使用 direct 交换机改进了我们的系统&#xff0c;但是它仍然存在局限性——比方说我们的交换机绑定了多个不同的routingKey&#xff0c;在direct模式中虽然能做到有选择性地接收日志&#xff0c;但是它的选择性是单一的&#xff0c;就是说我的一条消息…

JavaSE 常见问题解析

最近正在复习Java八股&#xff0c;所以会将一些热门的八股问题&#xff0c;结合ai与自身理解写成博客便于记忆 本文将以以上问题作为基础 String 相关问题 String 底层数据类型&#xff1f; String 在 Java 9 之前底层使用 char[] 数组存储字符数据&#xff0c;Java 9 及以…

潜入水面:穿越“冰山”之旅,探寻Java鲜为人知的一面

“冰山”梗是一种网络现象&#xff0c;幽默而有时令人不安地展示了某个主题的知识或入门层次——从冰山之巅简单、广为人知的常识到只有最坚韧的老兵才能理解的黑暗、神秘深处。想象一座海洋上矗立的冰山&#xff1a;表面可见的部分只是开始&#xff0c;真正的魔法&#xff08;…

如何配置mvn镜像源为华为云

如何配置mvn镜像源为华为云 # 查找mvn 配置文件 mvn -X help:effective-settings | grep settings.xml# 配置mvn镜像源为华为云&#xff0c;/home/apache-maven-3.9.5/conf/settings.xml文件路径需要根据上一步中查询结果调整 cat > /home/apache-maven-3.9.5/conf/setting…

【DAY37】早停策略和模型权重的保存

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点&#xff1a; 过拟合的判断&#xff1a;测试集和训练集同步打印指标模型的保存和加载 仅保存权重保存权重和模型保存全部信息checkpoint&#xff0c;还包含训练状态 早停策略 作业&#xff1a; 对信贷数据集训练后保存权…

TASK OA 案例hook

TASK OA 案例hook 定义的状态 useRef & useForm ref使用&#xff1a; xxx 尽可能使用组件库antd内部提供的方法 两大稍微比较难的组件&#xff1a;table 和 form 服务器通信 使用async/await 不用想配套使用 try/catch 初次渲染拉取query。useEffect(..., []) 状态更新useE…

Kafka集成Flume/Spark/Flink(大数据)/SpringBoot

Kafka集成Flume Flume生产者 ③、安装Flume&#xff0c;上传apache-flume的压缩包.tar.gz到Linux系统的software&#xff0c;并解压到/opt/module目录下&#xff0c;并修改其名称为flume Flume消费者 Kafka集成Spark 生产者 object SparkKafkaProducer{def main(args:Array[S…

Linux指令:

我们今天来学习一下linux的一些相关的指令L&#xff1a; 1. 快速认识6~8个指令&#xff1a; 第一条&#xff1a;pwd pwd指令表示的是我当前在哪条路径下&#xff1b;我当前在哪里&#xff1b; 我们看这个第二句话&#xff0c;因为在windows环境下&#xff0c;当我们登录进入到…

网络攻防技术五:网络扫描技术

文章目录 一、网络扫描的基础概念二、主机发现三、端口扫描1、端口号2、端口扫描技术3、端口扫描隐秘策略 四、操作系统识别五、漏洞扫描六、简答题1. 主机扫描的目的是什么&#xff1f;请简述主机扫描方法。2. 端口扫描的目的是什么&#xff1f;请简述端口扫描方法及扫描策略。…

win32相关(虚拟内存和物理内存)

虚拟内存和物理内存 在win32操作系统下&#xff0c;每个进程都有它自己独立的4GB空间&#xff0c;是window给它分配的一个虚拟空间&#xff0c;并不是真正的物理空间&#xff0c;这4GB空间中&#xff0c;分为高2G和低2G&#xff0c;高2G是应用程序的&#xff0c;低2G空间是给内…

00后新人“整顿”婚礼 简简单单更实在!

00后新人“整顿”婚礼简简单单更实在!婚礼当天,宾客们刚坐下,新郎新娘就手拉手走上台。新郎咧嘴一笑:“感谢各位来捧场,我俩今天正式领证了!”新娘接茬:“废话不多说,大家吃好喝好,菜不够再加,吃不完打包带走!”台下瞬间爆发出欢呼声,这场婚礼从开始到宣布开席,总…

德约科维奇vs诺里 法网百胜里程碑

北京时间6月2日,法网男单第四轮比赛中,赛会六号种子德约科维奇以6-2、6-3、6-2的比分击败诺里,成功晋级八强。首盘开始,德约连保带破取得2-0领先。尽管诺里随后回破,但德约在第四局再次破发,掌控了比赛节奏。最终在诺里的关键发球局中,德约再次破发,以6-2赢得首盘。第二…

地磁暴又来了!这些地方受影响 我国北部或现极光

中国气象局国家空间天气监测预警中心报告称,北京时间5月31日太阳爆发了耀斑,地球可能连续三天发生地磁暴,我国北部有机会出现较为明显的极光。具体来说,5月31日7点45分左右,太阳活动区14100开始爆发耀斑,软X射线流量快速上升,8点05分达到峰值——M8.1级中等耀斑强度。伴…

北京今天晴朗伴大风 阵风可达6至7级 明起炎热升级 气温将明显升高

今天6月3日,北京天气以晴朗为主,北风加大,阵风可达6至7级。未来两天,北京将继续保持晴朗,气温显著升高。昨天,北京大部分地区晴朗,北部和西部出现分散性阵雨或雷阵雨,但雨量不大。多地北风强劲,阵风达到6至7级。据北京市气象台预计,今天白天晴间多云,北风从2级左右逐…

全都要!德天空:新月将和胜利争夺C罗,同时致力于签下B费 沙特豪门雄心勃勃

据德国天空体育报道,利雅得新月在与利雅得胜利争夺C罗的同时,还致力于签下布鲁诺-费尔南德斯。C罗与利雅得胜利的合同将于6月底到期。尽管利雅得胜利的体育总监耶罗极力挽留,但利雅得新月希望签下这名40岁的老将,并带他参加即将举行的世俱杯(6月14日至7月13日)。利雅得新…

[HTML5]快速掌握canvas

背景 canvas 是 html5 标准中提供的一个标签, 顾名思义是定义在浏览器上的画布 通过其强大的绘图接口&#xff0c;我们可以实现各种各样的图形&#xff0c;炫酷的动画&#xff0c;甚至可以利用他开发小游戏&#xff0c;包括市面上很流行的数据可视化框架底层都用到了Canvas。…

Mininconda3安装使用

一、简介 Anaconda和Miniconda都是非常流行的Python发行版&#xff0c;它们都提供了强大的包管理系统和环境管理系统&#xff0c;让Python编程变得超级简单。 但Miniconda是Anaconda的精简版&#xff0c;只包含最基本的conda包管理器和Python环境管理器&#xff0c;不像Anaco…

设备驱动与文件系统:03 生磁盘的使用

磁盘驱动学习开篇 从这一讲开始&#xff0c;我们进入设备驱动的学习&#xff0c;具体聚焦于设备管理的最后一个部分——磁盘管理。磁盘管理实践也是操作系统课程的最后一块内容。磁盘的驱动器本质上仍是一种设备驱动&#xff0c;其原理不变&#xff0c;核心依旧是文件视图、磁…

【MATLAB代码】制导——平行接近法,三维,目标是运动的,订阅专栏后可直接查看MATLAB源代码

文章目录 运行结果简介代码功能概述运行结果核心模块解析代码特性与优势 MATLAB例程代码调整说明相关公式视线角速率约束相对运动学方程导引律加速度指令运动学更新方程拦截条件判定 运行结果 运行演示视频&#xff1a; 三维平行接近法导引运行演示 简介 代码功能概述 本代码…