JDK中有这么两个可视化工具:JConsole和VisualVM,它们是JDK的正式成员。
JConsole:Java监视与管理控制台
JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视、管理工具。
启动JConsole
进入到JDK/bin目录下,通过“jconsole.exe”启动JConsole。程序将自动搜索出本机运行的所有虚拟机进程,不需要用户自己再使用jps来查询了。
双击选择其中一个进程即可开始监控,也可以使用下面的“远程进程”功能来连接远程服务器,对远程虚拟机进行监控。
内存监控
“内存”页签相当于可视化的jstat命令,用于监视受收集器管理的虚拟机内存(Java堆和永久代)的变化趋势。
JConsole监视代码
/**
*内存占位符对象,一个OOMObject大约占64KB
*/
static class OOMObject{
public byte[]placeholder=new byte[64*1024];
}
public static void fillHeap(int num)throws InterruptedException{
List<OOMObject>list=new ArrayList<OOMObject>();
for(int i=0;i<num;i++){
//稍作延时,令监视曲线的变化更加明显
Thread.sleep(50);
list.add(new OOMObject());
}
System.gc();
}
public static void main(String[]args)throws Exception{
fillHeap(1000);
}
运行时设置的虚拟机参数为:-Xms100m-Xmx100m-XX:+UseSerialGC,这段代码的作用是以64KB/50毫秒的速度往Java堆中填充数据,一共填充1000次。
程序运行后,在“内存”页签中可以看到内存池Eden区的运行趋势呈现折线状。而监视范围扩大至整个堆后,会发现曲线是一条向上增长的平滑曲线。并且从柱状图可以看出,在1000次循环执行结束,运行了System.gc()后,虽然整个新生代Eden和Survivor区都基本被清空了,但是代表老年代的柱状图仍然保持峰值状态,说明被填充进堆中的数据在System.gc()方法执行之后仍然存活。
线程监控
“线程”页签的功能相当于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析。
线程等待演示代码
/**
*线程死循环演示
*/
public static void createBusyThread(){
Thread thread=new Thread(new Runnable(){
@Override
public void run(){
while(true)//第41行
;
}
},"testBusyThread");
thread.start();
}
/**
*线程锁等待演示
*/
public static void createLockThread(final Object lock){
Thread thread=new Thread(new Runnable(){
@Override
public void run(){
synchronized(lock){
try{
lock.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
},"testLockThread");
thread.start();
}
public static void main(String[]args)throws Exception{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
br.readLine();
createBusyThread();
br.readLine();
Object obj=new Object();
createLockThread(obj);
}
程序运行后,首先在“线程”页签中选择main线程,如图所示。堆栈追踪显示BufferedReader在readBytes方法中等待System.in的键盘输入,这时线程为Runnable状态,Runnable状态的线程会被分配运行时间,但readBytes方法检查到流没有更新时会立刻归还执行令牌,这种等待只消耗很小的CPU资源。
接着监控testBusyThread线程,testBusyThread线程一直在执行空循环,从堆栈追踪中看到一直在MonitoringTest.java代码的41行停留,41行为:while(true)。这时候线程为Runnable状态,而且没有归还线程执行令牌的动作,会在空循环上用尽全部执行时间直到线程切换,这种等待会消耗较多的CPU资源。
testLockThread线程在等待着lock对象的notify或notifyAll方法的出现,线程这时候处于WAITING状态,在被唤醒前不会被分配执行时间。
VisualVM:多合一故障处理工具
VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。
VisualVM的还有一个很大的优点:不需要被监视的程序基于特殊Agent运行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中。这个优点是JProfiler、YourKit等工具无法与之媲美的。
各位看官请自己下载摸索…
总结
除了JDK自带的工具之外,常用的故障处理工具还有很多,如果读者使用的是非Sun系列的JDK、非HotSpot的虚拟机,就需要使用对应的工具进行分析,如:
- IBM的Support Assistant、Heap Analyzer、Javacore Analyzer、Garbage CollectorAnalyzer适用于IBM J9 VM。
- HP的HPjmeter、HPjtune适用于HP-UX、SAP、HotSpot VM。
- Eclipse的Memory Analyzer Tool(MAT)适用于HP-UX、SAP、HotSpot VM,安装IBMDTFJ插件后可支持IBM J9 VM。
- BEA的JRockit Mission Control适用于JRockit VM。