安装使用
curl -O https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar
执行该程序的用户需要和目标进程具有相同的权限,最好和目标进程的用户一致
启动以后,输入 数字 选择要观察的进程,也可增加--select jar名称自动选择进程,提高操作效率
还可以在 末尾增加 进程号(启动后也不用选择进程了)
查看 dashboard
输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。
watch
通过watch命令来查看demo.MathGame#primeFactors函数的返回值:
观察指定函数的调用情况,如 入参、返回值、抛出异常,通过编写 OGNL 表达式查看
命令格式:watch 类全名或类名表达式 函数名表达式 {观察表达式} -x 输出深度 -n 次数
观察表达式:默认 {params, target, returnObj},分别是 参数列表、被观察对象、返回值
-x 输出深度:默认为 1,最大为 4。默认的 观察表达式中 params + 输出深度 1,只能输出 params 是否 empty,size 是 几,要看到内容就要加大 输出深度 或 改为 params[0]
很多时候,我们都不关注 被观察对象 target,指定 观察表达式 可以降低干扰,尤其是 属性多 或 输出深度大的时候
观察执行频繁的方法,最好指定 -n 次数,避免刷屏
条件表达式的例子
只有满足条件的调用,才会有响应。第一个参数值小于0才显示。
[arthas@421]$ watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 20 ms, listenerId: 2
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2023-12-07 15:06:54; [cost=0.122501ms] result=@ArrayList[
@Integer[-162810],
@MathGame[demo.MathGame@5910e440],
]
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2023-12-07 15:06:56; [cost=0.023808ms] result=@ArrayList[
@Integer[-26281],
@MathGame[demo.MathGame@5910e440],
]
重载todo
重载方法,可通过参数 个数、类型 筛选
命令格式:watch 类全名或类名表达式 函数名表达式 {观察表达式} 'params.length== 参数个数 && params[1] instanceof java.lang.String
[arthas@22882]$ watch demo.MathGame primeFactors "{params[0],params[1],target}" "params.length==2 && params[1] instanceof java.lang.String"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 2) cost in 15 ms, listenerId: 15
method=demo.MathGame.primeFactors location=AtExit
ts=2023-12-07 15:30:10; [cost=0.225008ms] result=@ArrayList[
@Integer[1],
@String[cz],
@MathGame[demo.MathGame@533ddba],
]
退出 arthas
如果只是退出当前的连接,可以用quit或者exit命令。Attach 到目标进程上的 arthas 还会继续运行,端口会保持开放,下次连接时可以直接连接上。
如果想完全退出 arthas,可以执行stop命令。
源码:
package demo;
import java.util.ArrayList;
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();
while (true) {
game.run();
TimeUnit.SECONDS.sleep(1);
game.run1();
TimeUnit.SECONDS.sleep(1);
}
}
public void run() throws InterruptedException {
try {
int number = random.nextInt() / 10000;
List<Integer> primeFactors = primeFactors(number);
print(number, primeFactors);
} catch (Exception e) {
System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage());
}
}
public void run1() throws InterruptedException {
try {
int number = random.nextInt() / 10000;
List<Integer> primeFactors = primeFactors(number, "cz");
print(number, primeFactors);
} catch (Exception e) {
System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage());
}
}
public static void print(int number, List<Integer> primeFactors) {
StringBuffer sb = new StringBuffer(number + "=");
for (int factor : primeFactors) {
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) {
illegalArgumentCount++;
throw new IllegalArgumentException("number is: " + number + ", need >= 2");
}
List<Integer> result = new ArrayList<Integer>();
int i = 2;
while (i <= number) {
if (number % i == 0) {
result.add(i);
number = number / i;
i = 2;
} else {
i++;
}
}
return result;
}
public List<Integer> primeFactors(int number, String name) {
System.out.println("number:" + number + "primeFactors override method");
if (number < 2) {
illegalArgumentCount++;
throw new IllegalArgumentException("number is: " + number + ", need >= 2");
}
List<Integer> result = new ArrayList<Integer>();
int i = 2;
while (i <= number) {
if (number % i == 0) {
result.add(i);
number = number / i;
i = 2;
} else {
i++;
}
}
return result;
}
}