arthas诊断线上java应用

背景:

想起来之前的面试,有一次问到:假如线上出现cpu飙升,和内存问题,如何排查?当时我只用过jprofiler,现在想想这个玩意是要占用一个端口的,而且会影响服务器的性能,适用于开发压测阶段。 如果是想立刻查看一个运行的java信息,则必须使用arthas这种无入侵的工具了。

0)arthas命令列表

命令列表 | arthas (aliyun.com)

1)下载arthas

curl -O https://arthas.aliyun.com/arthas-boot.jar

2)运行jar包启动

思考:可以看出来,arthas对java应用没有任何入侵。

3)然后选择对应的进程ID

4)打开网页版本 

Arthas Console

5)常用命令

1.dashboard  // 当前进程的信息

笔记:

感觉比较有用的就是: 堆信息,操作系统java_home信息。

2.jvm // 查看当前jvm信息

笔记:

直接看出来死锁了。

3.mbean // 查看mbean的信息

4.memory // 查看jvm内存信息

5.sysenv

6.thread -all // 打印jvm线程堆栈信息   

7.thread -n 5  // 打印cpu占比最高的5个线程

8.redefine // 线上热更新类

使用:

redefine C:\Users\elex\Desktop\Main.class

测试结果:发现从v2变为了v1, 热更生效了 

注意:写到死循环中是不行的,找不到安全点???

9.jad  // 查看线上的代码(包名+类名)。

10.清空控制台

cls

11.trace // 监听某个类中某个方法的耗时

红色的,看下是否合理,如果不合理,进一步查看红色的。

例子:

step1:先用thread -n 10定义排名前10的线程,然后看看这个线程干什么的,找到run方法体

step2: 使用trace排查下这个方法中哪里执行时间长

[arthas@14394]$ trace com.elex.icefire.scene.AbstractSceneManager execute -n 10
Press Q or Ctrl+C to abort.
Affect(class count: 2 , method count: 1) cost in 387 ms, listenerId: 1
`---ts=2024-01-20 15:19:41;thread_name=BigWorldSceneManager;id=66;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@7aec35a
    `---[100.520698ms] com.elex.icefire.scene.AbstractSceneManager:execute()
        +---[0.02% 0.016681ms ] com.elex.icefire.scene.utils.SceneClock:now() #94
        +---[25.35% 25.484375ms ] com.elex.icefire.scene.utils.SceneExecutor:forEach() #97
        `---[0.01% 0.007855ms ] com.elex.icefire.scene.utils.SceneClock:now() #99

[arthas@14394]$ trace com.elex.icefire.scene.utils.SceneExecutor forEach -n 10
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 181 ms, listenerId: 3
`---ts=2024-01-20 15:21:22;thread_name=SceneWorker-thread-1;id=112;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@7aec35a
    `---[5.112861ms] com.elex.icefire.scene.utils.SceneExecutor:forEach()
        `---[98.72% 5.047168ms ] com.elex.billion.icefire.core.thread.ThreadUtils:forEach() #49


[arthas@14394]$ trace com.elex.billion.icefire.core.thread.ThreadUtils forEach -n 10
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 181 ms, listenerId: 4
`---ts=2024-01-20 15:23:26;thread_name=SceneWorker-thread-1;id=112;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@7aec35a
    `---[8.183661ms] com.elex.billion.icefire.core.thread.ThreadUtils:forEach()
        `---[0.24% 0.019938ms ] com.google.common.collect.Lists:partition() #54


      // 如果对象集过大,异步轮询时会构建大量异步任务,这时可以将集合进行分块,减少异步任务的构建
            List<List<V>> partitionList = Lists.partition(new ArrayList<>(collection), partition);
            CompletableFuture.allOf(partitionList.stream().map(list -> CompletableFuture.runAsync(() -> listObjectAction(list, action), workers))
                    .toArray(CompletableFuture[]::new)).join();

12.stop //停止arthas

13. profiler //cpu火焰图