三、可视化工具
JDK 提供大量的命令行工具外,还提供了两个功能强大的可视化工具 JConsole 和 VIsualVM,还有一个常用的商用工具 JProfiler,它们提供可视化界面,比前面的命令行工具使用起来更简单,监控内存数据更直观。
1. JConsole
JConsole(Java Monitoring and Management Console)是一种基于 JMX 的可视化监视、管理工具,我们可以在JAVA_HOME/bin
目录下找到它,启动后可以直接连接本地虚拟机进程,也可以使用远程进程来连接远程服务器。它可以监控的内容有:
Memory
:监视虚拟机内存,相当于 jstat 命令。Threads
:监控虚拟机线程,相当于 jstack 命令。Classes
:查看 Java 类加载的信息。VM Summary
:查看 JVM 摘要信息。MBeans
:查看所有 MBeans 的信息。
2. VisualVM
VisualVM(All-in-One Java Troubleshooting Tool)多合一故障处理工具是到目前为止随 JDK 发布的功能最强大的运行监视和故障处理工具,除此之外它还提供了很多其他方面的功能,如性能分析(Profiling),VisualVM 的性能分析功能比 JProfiler、YourKit 等专业且收费的工具都不会逊色,而且它不需要被监视的程序基于特殊 Agent 运行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中。我们可以通过运行 JAVA_HOME/bin/jvisualvm.exe
来启动它。
VisualVM 除了监视各种内存状况、查看类转储文件之外,还支持添加各种插件来扩展它的功能,例如添加 BTrace 插件来进行动态日志跟踪,它可以在不停止目标程序运行的前提下,通过 HotSpot 虚拟机的 HotSwap 技术动态加入原本并不存在的调试代码,我们经常会遇到程序出现问题,但排查错误的一些必要信息,比如方法参数、返回值等,在开发时并没有打印到日志当中,正常情况下需要停掉服务,加入日志代码来解决问题,而使用 BTrace 则不需要。假设我们存在下面代码程序:
public class Main { public static int add(int a, int b) { return a + b; } public static void main(String[] args) { System.out.println("Hello GC"); try { Thread.sleep(30000); for (int i = 0, n = 10; i < n; i++) { System.out.println(add(1, 2)); } Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } }
在 VisualVM 中安装 BTrace 插件后,右击需要调试的程序点击Trace Application...菜单,进入 BTrace 面板,在里面编写代码如下:
BTrace 的用法还有很多,打印调用堆栈、参数、返回值只是最基本的应用,还可以用来性能监视、定位连接泄漏和内存泄漏、解决多线程竞争问题等。
3. JProfiler
JProfiler 是一个商业授权(收费)的 Java 性能分析工具,针对 Java SE 和 Java EE 应用程序开发,它的主要功能有:
- 内存分析:显示所有对象数量和占用内存
- 堆遍历:显示堆中所有类和它们的实例
- CPU 分析:监控 CPU 使用情况
- 线程分析:线程历史、线程监控、死锁探测等等
查看应用程序运行时类的实例个数和占用空间大小。
四、实战
Windows 下模拟及排查 CPU 占用高的问题
首先编写运行下面代码来模拟 CPU 占用高的场景:
public class CPU { public static void main(String[] args) { int i = 0; while (true) { i++; } } }
在 Windows 系统下通过任务管理器来找到 CPU 占用高的 Java 进程,此时可以确定 CPU 占用高的应用程序进程号为 17368。
也可以使用命令jps -l
来查看该进程下的 Java 应用程序。
在 Windows 下面不能直接查看到 CPU 占用高的应用程序中哪个线程 CPU 占用高,所以需要下载 Process Explorer 工具来查看,如下图,找到 CPU 占用高的应用进程。
然后右击进程进入属性界面,再点击Threads
菜单项,就可以找到 CPU 占用高的线程 ID 为 17176。
通过计算器或其他方法将 17176 转换成十六进制格式为0x4318
,最后使用jstack 17368
来查看应用线程堆栈信息,定位到nid=0x4318
的线程,就可以找到 CPU 占用高的程序代码了。
Linux 下模拟及排查 CPU 占用高的问题
在 Linux 下的操作过程和 Windows 下的一样,只是使用工具更简单,首先在服务器上运行同样的代码来模拟 CPU 占用过高的场景,然后使用top
命令来定位,CPU 占用过高的 Java 程序进程为 18119。
使用top H -p 18119
来查找该进程下的线程状态,可以定位到 CPU 占用过高的线程 ID 为 18120。
使用下面命令将 18120 转换成十六进制为46c8
,最后使用 jstack 命令来定位出现 CPU 占用高的问题代码。
$ printf %x 18120 46c8 $ jstack 18119|grep -A10 46c8
线上发生问题时,需要冷静分析,配合使用工具来快速定位到线上问题,是一个合格的程序员所必备的技能。