Java Performance - 如何调查解决 CPU 问题
随着硬件的发展,往往服务器会配置足够的 CPUs, Java Server/服务器不太有 CPU 问题;但是偶尔因为 代码海量循环 或者 线程安全性(thread safe), 还是会带来 CPU 问题:
OS 现象:
-
- Windows 上面,发现 Java 进程CPU高,注意 Task Manager/ Resource Monitor 里面的 CPU 百分比是 所有 CPU 百分比;比如 16个 CPU, 如果看到 50%,表示用了 8 个 CPU。
- IBM AIX - 发现 Java 进程CPU高,注意 topas 里面的 CPU 百分比是 所有 CPU 百分比;比如 16个 CPU, 如果看到 50%,表示用了 8 个 CPU。
- Linux/Solaris - 注意 top 里面的 CPU 百分比是 单个 CPU 百分比;比如 16个 CPU, 如果使用了 8 个CPU,会看到 800%
常见问题以及诊断方法:
- 线程安全性(thread safe):
- 现象:CPU 持续很高,永不释放,而且会越来越高。
- 常见原因:比如 HashMap, 同时进行 put 引起损坏,然后后续的 get 也彻底陷入死循环
- 调查方法: jstack <pid> 抓取thread dump, 看到很多线程卡在 HashMap.get() / HashMap.put(); 需要修改代码比如通过 synchronized HashMap 的 put() 或者改用 ConcurrentHashMap
- 代码海量循环引起的 CPU 问题
- 使用 CPU Profiler/Sampler 调查:
jvisualvm 里面的 CPU Profiler
连到 JVM 后,到 Sampler, Click #CPU in the VisualVM and start your request; after complete the request, click #STOP in the VisaulVM
- 通过操作系统层面调查
-
-
- IBM AIX Java
-
1. topas 命令定位 CPU 使用高的进程,比如下面 PID 614852
Name PID CPU%
java
614852 23.9
java
450806 20.5
2. 使用命令 ps -mp <PID> -o THREAD 定位 CPU 使用高的线程 TID
比如下显示线程 (TID)11219165 消耗了 22% CPU. 把 11219165 换成 16 进制得到 AB30DD
ps
-mp 614852 -o THREAD
USER PID PPID
TID S CP PRI SC
WCHAN F TT
BND COMMAND
wc90 614852
581756 - A 222 60
49 *
242001 - - xxxxxxxxxxxx
- - - 4751559
R 20 95 1
- 400000 - - -
- - -
11219165 R 22 96 0
- 400000 - - -
3. 获得 javacore 文件
通过命令 kill -3 <pid>, 比如 kill -3 614852
硬盘上 Java 工作目录 (一般是启动目录)会产生 javacore.20150507.163756.643532.0004
4. 搜索 TID, 比如 会得到线程的 Stack Trace, 然后可以定位消耗 CPU 的代码
-
-
- Java 在 Linux 或者 Solaris
-
1. 和上面类似,不过使用下面命令得到消耗 CPU 的 进程以及里面的线程
ps H -eo
user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu
Or
top -H -p <pid>
2. 使用下面命令抓取 进程 thread dump, 然后结合上面的 PID (需要换成 16 进制),在 thread dump 里面搜索就可以找到
Jstack <pid> > jstack.txt