Java与C++之间有一睹由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。
Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
Arthas(阿尔萨斯) 能为你做什么?
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
1.启动Arthas
https://arthas.aliyun.com/doc/quick-start.html 请看官方到快速入门,下载好Arthas jar包到本地
入门的第一步下载官方的demo,然后启动,通过jps 获取进程id,在启动Arthas jar包,然后进行诊断
2.使用Arthas
这里自己有一个dmeo例子,用于死锁的代码实例:
@Slf4j
public class ArthasTest {
private static Logger log = Logger.getLogger("MyLogger");
private static HashSet hashSet = new HashSet();
/** 线程池,大小1*/
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
public static void main(String[] args) {
// 模拟 CPU 过高,这里注释掉了,测试时可以打开
// cpu();
// 模拟线程阻塞
thread();
// 模拟线程死锁
deadThread();
// 不断的向 hashSet 集合增加数据
addHashSetThread();
}
/**
* 不断的向 hashSet 集合添加数据
*/
public static void addHashSetThread() {
// 初始化常量
new Thread(() -> {
int count = 0;
while (true) {
try {
hashSet.add("count" + count);
Thread.sleep(10000);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public static void cpu() {
cpuHigh();
cpuNormal();
}
/**
* 极度消耗CPU的线程
*/
private static void cpuHigh() {
Thread thread = new Thread(() -> {
while (true) {
log.info("cpu start 100");
}
});
// 添加到线程
executorService.submit(thread);
}
/**
* 普通消耗CPU的线程
*/
private static void cpuNormal() {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
log.info("cpu start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* 模拟线程阻塞,向已经满了的线程池提交线程
*/
private static void thread() {
Thread thread = new Thread(() -> {
while (true) {
// log.debug("thread start");
log.info("thread start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 添加到线程
executorService.submit(thread);
}
/**
* 死锁
*/
private static void deadThread() {
/** 创建资源 */
Object resourceA = new Object();
Object resourceB = new Object();
// 创建线程
Thread threadA = new Thread(() -> {
synchronized (resourceA) {
log.info(Thread.currentThread() + " get ResourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(Thread.currentThread() + "waiting get resourceB");
synchronized (resourceB) {
log.info(Thread.currentThread() + " get resourceB");
}
}
});
Thread threadB = new Thread(() -> {
synchronized (resourceB) {
log.info(Thread.currentThread() + " get ResourceB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(Thread.currentThread() + "waiting get resourceA");
synchronized (resourceA) {
log.info(Thread.currentThread() + " get resourceA");
}
}
});
threadA.start();
threadB.start();
}
}
这里就是启动成功了,我们进入了test的进程id程序中,然后我们就可以使用官方文档上面的命令进行分析,注意这里的命令和linunx中的差不多
3.使用Arthas 命令进行分析
https://arthas.aliyun.com/doc/advanced-use.html 官方文档中,列出了很多的命令,有不同功能的
dashboard
当前系统的实时数据面板,按 ctrl+c 退出。
dashboard
实时打印出jvm的信息,以及gc的情况
thread
查看当前线程信息,查看线程的堆栈
class/classloader相关
sc 查看JVM已加载的类信息
最后推荐大家看看阿里推荐的arthas用户案例分析,看看大家都是这么在项目中去使用 arthas 去处理线上问题的
https://github.com/alibaba/arthas/issues/1202
可以学习一波经验,好了,一起学习,加油