JVM学习总结五(番外)——JConsole

    以前原本打算结合本身写的小程序来介绍JConsole和VisualVM的使用的,可是发现很难经过一个程序把全部的场景都体现出来,因此仍是决定用书中的典型小例子来说更加清晰。 java

1、JConsole的基本功能

    JConsole是一个机遇JMX(Java Management Extensions,即Java管理扩展)的JVM监控与管理工具,监控主要体如今:堆栈内存、线程、CPU、类、VM信息这几个方面,而管理主要是对JMX MBean(managed beans,被管理的beans,是一系列资源,包含对象、接口、设备等)的管理,不只能查看bean的属性和方法信息,还可以在运行时修改属性或调用方法。
    首先咱们看下JConsole的启动,JConsole在jdk/bin/下,其启动须要图形界面的支持(废话,都说了图形界面),可能很多人一听到这个就以为有点low:平时服务器跑的linux都没图形界面,那岂不是用不了。其实不用担忧,JConsole支持远程进程监测。下边是链接界面,其实至关于jps命令:
linux

    再来看下链接后的界面,咱们打开DeadLock(一个测试死锁的示例): 算法

能够看到上边的选项卡正好对应各个功能。
小程序

一、概述

    这个不介绍了,就是上图,相信你们都看的懂。

二、内存

    在内存页咱们能够看到程序运行期间JVM各个部分的内存情况,右下角是对应各个分区的内存使用柱状图,点击对应柱可查看详情,看图:

三、线程

    该页面能够查看当前JVM进程启动了多少个线程,并能查看每一个线程的状态及堆栈信息,此外还有一个功能就是可以自动检测死锁,见图:     

四、类

    该页面其实和线程页有些类似,不过显示的是JVM加载类的信息,见图:

五、VM概述

    这个其实不必细说,看图就明白,显示了当前JVM的各方面信息:

六、MBean管理

    这一部分也不细说,主要目前本身对JMX MBean不太熟悉,想要深究的就本身研究吧:

     下边来看两个小示例,分别分析内存和死锁的。 缓存

2、两个示例

一、内存分析

    这里咱们来经过一个小程序进行一下内存分析,代码以下:
package com.gj.jconsole;

import java.util.ArrayList;
import java.util.List;

public class DataInsert {

	//一个OOMObject实例大概64k+
	static class OOMObject{
		public byte[] placeholder= new byte[64*1024]; 
	}
	
	public static void fillHeap() throws InterruptedException {
		List<OOMObject> list =new ArrayList<OOMObject>();
		for(int i=0;i<1000;i++){ 
                        Thread.sleep(100);
			list.add(new OOMObject());
		}
		System.gc();
	}

	public static void main(String[] args) throws Exception{
		fillHeap();
	}
}
    能够看到程序向list中插入了1000个OOMObject对象,每一个OOMObject大概64k,那么堆内存的峰值应该在64k*1000=64m左右,咱们运行程序,并使用JConsole打开DataInsert进程,当程序结束时堆内存以下:


    能够看到对内存峰值在60-70m之间(下方已用内存为63631kb,大约63m),与咱们预计的相符。下边咱们来看下下边这段代码: 服务器

package com.gj.jconsole;

import java.util.ArrayList;
import java.util.List;

import com.gj.jconsole.DataInsert.OOMObject;

public class GCTest {

	// 一个OOMObject实例大概640k+
	static class OOMObject {
		public byte[] placeholder = new byte[64 * 1024*10];
	}
	
	public static void fillHeap() throws InterruptedException {
		for(int i=0;i<100;i++){
			OOMObject oOmObject =new OOMObject();
			Thread.sleep(1000);
			oOmObject=null;
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		fillHeap();
	}

}
    这段代码每次新建一个OOMObject对象,在暂停1s后将其置null,咱们来看下运行时内存图:

    会发现堆内存呈规律的折线,咱们来分析下:当每一个对象实例化后,而后置null,这时候对象并不会被回收(由于没有gc),所以内存会一直上升,可是当堆内存不够用时,会触发gc,所以内存会下降。查看VM概况可知,一共进行了18次gc,回收算法为“复制”。 多线程

二、线程死锁

    经过Jconsole不只能够查看线程信息,并且可以检测死锁,先来看下代码:
package com.gj.jconsole;

public class DeadLock {

	static class SynAddRunable implements Runnable{
		int a,b;
		public SynAddRunable(int a,int b){
			this.a= a;
			this.b= b;
		}
		@Override
		public void run() {
			synchronized (Integer.valueOf(a)) {
				synchronized (Integer.valueOf(b)){
					System.out.println(a+b);
				}
			}
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		for(int i=0;i<100;i++){
			new Thread(new SynAddRunable(1, 2)).start();
			new Thread(new SynAddRunable(2, 1)).start();
		}
	}
}
    能够看到代码中启动200个子线程,进行1+2或2+1的计算,可是这种状况为何会出现死锁呢?咱们看到在run中出现双重sychronized,这是典型的死锁特征, 可是这种状况要出现死锁前提是多线程中 sychronized同步的两个对象分别都是同一个,才会形成互锁,可是Integer.valueOf(a)和Integer.valueOf(b) 每次返回的不都是一个新对象吗?这里须要注意一个问题,为了节省内存,对于[-128,127]之内的转换, Integer.valueOf会将这些值从缓存直接返回,因此相同的值返回的都是同一个对象(记得看java源码的时候见过不少这种处理方法)。 好了,来看下如何检查死锁。
    等程序运行一段时间以后(这种状况下造成死锁是随机的,并不能肯定那两个会互锁,可是对于200个线程几率仍是很是大的 ),咱们在线程页点击“检测死锁”,则会多出来一个死锁页,打开能够看到以下信息:



    能够看到线程0和线程11互锁,同时线程199因为等待线程11释放锁,也被阻塞。

    以上就是JConsole的基本用法,仍是比较简单的。但这些只是小道,工具毕竟只是辅助,关键的仍是要懂得原理,学会分析,真正的能在实践中活用才好。下次将介绍更为强大的VisualVM,敬请期待喽^_^。 ide

相关文章
相关标签/搜索