背景:
想起来之前的面试,有一次问到:假如线上出现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火焰图