JAVA運行時問題診斷-工具應用篇

該BLOG內容是以前在部門組織討論運行時問題時本身寫的PPT內容,內容以點帶面,主要是方便之後本身回顧查看。java

大綱包括:一、運行時問題分類 二、服務器自帶工具 三、其餘工具 四、例子 五、實際狀況服務器

運行時問題分類-軟件角度:一、內存泄漏,對象未釋放 二、線程阻塞、死鎖 三、線程死循環 四、網絡IO鏈接超時時間過長 五、磁盤不可寫 .....網絡

運行時問題分類-硬件角度:一、內存佔用高 二、CPU佔用高 三、網絡無反應 四、硬盤空間滿 ....ide

Linux指令:一、top, top -Hp pid 二、free 三、df 四、netstat, netstat -natp ...工具

JDK指令:一、jps, jps -v 二、jstack, jstack pid 三、jmap, jmap -dump:format=b,file=/opt/...  四、jstat, jstat -gcutil(gc,gccapacity) pid ....網站

工具:ui

實時分析工具: 一、Jconsole 二、VisualVM  三、JProfiler  四、JavaMelody  五、LambdaProbe ....this

離線分析工具: 一、MemoryAnalyzer tool  二、Thread Dump Analyzer ....spa

DEMO:一、內存溢出  二、CPU佔用太高  三、線程死鎖  四、線程阻塞線程

準備工做:堆棧內存設置低一點,打印GC日誌和OOM時輸出dump文件: set JAVA_OPTS=-server -Xms24m -Xmx50m -XX:PermSize=28M -XX:MaxPermSize=80m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\temp\dump

內存溢出:

        Map<String, Person> map = new HashMap<String, Person>();
        Object[] array = new Object[1000000];
        for (int i = 0; i < 1000000; i++) {
            String d = new Date().toString();
            Person p = new Person(d, i);
            map.put(i + "person", p);
            array[i] = p;
        }

MAT-關鍵字(我的理解,不必定準確):

Histogram:內存中的類對象實例的對象的個數和大小

Dominator Tree:堆對象樹,對象大小和佔用百分比

Leak Suspects:MAT分析的內存泄漏的可疑點

shallow heap:對象自身佔用內存大小

retained heap:對象自身和引用的對象佔用內存大小

Merge Shortest Paths to GC Roots:從GC根節點到該對象的路徑視圖

with outgoing references:對象持有的外部對象引用

with incomming references:對象被哪些外部對象引用

....

 

CPU佔用太高:

		int i = 0;
		while (i < 1000000) {
			i++;
			System.out.println(i);
			try {
				Thread.sleep(0);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

  

 

線程死鎖:

		Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
		Thread t2 = new Thread(new SyncThread(obj2, obj1), "t2");

		t1.start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t2.start();
		synchronized (obj1) {
			System.out.println("主線程 lock on " + obj1.getName());
		}

  

	private Person obj1;
	private Person obj2;

	public SyncThread(Person o1, Person o2) {
		this.obj1 = o1;
		this.obj2 = o2;
	}

	public void run() {
		String name = Thread.currentThread().getName();
		System.out.println(name + " acquiring lock on " + obj1.getName());
		synchronized (obj1) {
			System.out.println(name + " acquired lock on " + obj1.getName());
			work();
			System.out.println(name + " acquiring lock on " + obj2.getName());
			synchronized (obj2) {
				System.out.println(name + " acquired lock on " + obj2.getName());
				work();
			}
			System.out.println(name + " released lock on " + obj2.getName());
		}
		System.out.println(name + " released lock on " + obj1.getName());
		System.out.println(name + " finished execution.");
	}

	private void work() {
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

  

 

線程阻塞:

		WaitThread thread1 = new WaitThread();
		thread1.setName("線程1");
		NotifyThread thread2 = new NotifyThread();
		thread2.setName("線程2");

		thread1.start();

		try {
			Thread.sleep(20000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		thread2.start();

  

public class NotifyThread extends Thread {
	@Override
	public void run() {
		synchronized (RequestThreadWait.object) {
			System.out.println("線程" + Thread.currentThread().getName() + "佔用了鎖");
			try {
				Thread.sleep(20000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			RequestThreadWait.object.notify();
			System.out.println("線程" + Thread.currentThread().getName() + "調用了object.notify()");
			try {
				Thread.sleep(20000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("線程" + Thread.currentThread().getName() + "釋放了鎖");
	}
}
public class WaitThread extends Thread {

	public void run() {
		synchronized (RequestThreadWait.object) {
			System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖開始");
			try {
				RequestThreadWait.object.wait();
			} catch (InterruptedException e) {
			}
			System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖結束!");
		}
	}
}

  

線程狀態(我的理解,不必定準確):

WAITING (parking):線程自身掛起等待,正常

WAITING (on object monitor):線程主動執行wait,等待資源,若是是本身的程序,須要關注

BLOCKED (on object monitor):線程阻塞,等待對方釋放資源,若是是互相等待對方阻塞的線程,則發生死鎖

TIMED_WAITING (on object monitor):線程調用了wait(long timeout),在特定時間內等待

TIMED_WAITING (sleeping):調用了sleeping,休眠一段時間

 

JavaMelody:

LambdaProbe

 

實際狀況:

用戶反饋各類千奇百怪的問題!

網絡訪問鏈接不上

網站、接口訪問超時

特定功能很慢

部分功能部分人打不開

.......

->

ping,telnet,traceroute....

top,top -Hp pid,jstack pid....

jstat -gc,gcutil,gccapacity pid...

jmap -dump:format=b,file=/opt/.... tail, df -lh....

netstat -natp....

.....

生產問題沒有統一解決辦法,具體問題具體分析

內存查看:jstat

線程狀況查看:top -Hp pid

CPU查看:jstack

網絡查看:netstat

 

實際問題分析:

線上查看 服務器狀況分析 獲取內存dump 獲取javacore

線下分析 工具調試分析內存線程

代碼調試 Eclipse Class Decompiler(自動反編譯,選擇JD-Core,精確行數)

...

轉載請註明:http://lawson.cnblogs.com

上面是實際生產問題的本身寫的PPT,copy下來的,JDK自帶的工具和指令比較強大,本篇文章沒有太多介紹。

相關文章
相關標籤/搜索