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

相關文章
相關標籤/搜索