通過《深入了解Java虛拟機》一書中,需要了很多,今天是對性能工具和故障處理的學習筆記:
在給系統定位問題的時候,知識,經驗是關鍵基礎,資料是依據,工具是處理資料的手段。此處所說的資料包括:GC日志,運作日志,異常堆棧,線程快照(Threaddump/javacore檔案),
堆轉儲快照(heapdump/hprof檔案)等。經常使用虛拟機監控和分析工具可以加快分析資料、定位解決問題的速度。
1)Java的指令行工具:bin下的Java.ext, javac.exe是運作和編譯工具,幾乎所有的體積都非常小,因為大多是類庫中的一層薄包裝,linux中的JDK,很多都是用shell腳本直接寫成的
jdk 的故障和監控工具如下所示:

jps:虛拟機程序狀況工具
是使用指令最高的JDK指令行工具,因為其他的JDK工具需要輸入的條件LVMID需要這個指令查詢出來,來确定要監控的程序是哪一個虛拟機程序。
jstat:虛拟機統計監控資訊工具
用于監控虛拟機各個運作狀态資訊的指令行工具。它可以顯示本地或者遠端上的類裝載,記憶體,垃圾收集,JIT編譯等運作時資料。在沒有GUI圖像界面時,隻提供純文字控制台環境的伺服器上,它将是定位運作期虛拟機性能問題的首選工具。
例如:jstat gc 2764 250 20: 表示需要250毫秒查詢一次程序2764垃圾收集情況,一共查詢20次
gc的位置可以換做其他的字段
jmap:Java記憶體映像工具,用于生成堆轉儲快照,一般成dump檔案或者heapdump檔案,還可以通過配置VM參數擷取:-XXHeapDumpOnOutOfMemoryError
例如:jmap -dump:format=b,file=eclipse.bin 3500 生成一個正在運作的eclipse的dump快照檔案的例子,後面的3500用于辨別程序,可通過jps查詢得知
jhat:虛拟機轉儲快照分析工具,與jmap搭配使用,結果分析後,可以在網頁上檢視具體情況,不過一般不這麼做,因為分析工具是一種耗時耗資源的程序,可放到其他機器上運作,且分析功能簡陋,再次不再叙述。
jstack:Java堆棧跟蹤工具,用于生成目前時刻的線程快照,目的是定位線程出現長時間停頓的原因,如線程間的死鎖,死循環,請求外部資源導緻長時間停頓的原因。
線程停頓的時候,通過jstack檢視各個線程的調用堆棧,就可以知道沒有響應的線程到底在背景做些什麼事情,或者在等待什麼資源。
jstack [option] vmid :option處有3中情況:
1)F:當正常輸入的請求不被響應時,強制輸出線程堆棧
2)-l:除堆棧外,顯示關于鎖的附加資訊
3)-m:如果調用到本地方法的話,可以顯示C/C++的堆棧
JConsole:JDK的可視化工具,自動搜尋出本機運作的所有虛拟機程序,不需要使用者自己再使用jps來查詢了,對遠端虛拟機程序監控。概覽頁有4部分,堆記憶體使用情況,線程,類,CPU使用情況。概覽是後面頁的概述情況。記憶體頁相當與可視化的jstat指令,用于監視收集器管理的虛拟機記憶體的變化趨勢。
下面針對記憶體頁的監視案例:
import java.util.ArrayList;
import java.util.List;
/**
* 記憶體占位符對象,一個Object對象大約占64K
* 虛拟機的參數設定為:-Xms100m -Xmx100m -XX:+UseSerialGC
*/
public class OOMObject {
public byte[] placeholder=new byte[64*1024];
public static void fileHeap(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 {
fileHeap(1000);
}
}
運作bin下的jconsole.exe,會出現
選擇你需要的程式檔案,比如OOMObject類,在運作時,就會在下拉框中出現這個類的選項,截圖如下所示;
下拉框可以選擇想看的記憶體區域,Eden Space 區域是呈折線狀的,擴大到整個堆後,是一條向上增長的曲線,老年代的圓柱仍然保持峰值,說明被填充進堆的資料在System.gc()後仍然存活,從這監控圖裡面,可以看出,Eden大小為27328KB,因為沒有設定-XXSurvivorRadio(設定survivor與Eden的比值)參數,采用的預設比例Eden:survivor=8:1.
則整個新生代空間大約為27328*125%=34160KB。
線程監控:
線程長時間等待的原因:等待外部資源(資料庫連接配接,網絡資源,裝置資源等),死循環,所等待(死鎖和活鎖)。
線程等待的示範執行個體代碼如下所示:
package com.three.twentynine;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestThread {
//線程死循環方法
public static void createBusyThread() {
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
while(true);//此處沒有跳出循環的條件限制,講話一直執行這句代碼,這個線程也就不能正常結束
}},"testBusyThread") ;
thread.start();
}
//線程鎖等待示範
public static void createLockThread(final Object lock) {
Thread thread=new Thread(new Runnable(){
@Override
public void run() {
synchronized(lock) {//此處的synchronized用來實作加鎖機制,隻有一個線程執行鎖住的代碼,其他線程需要等待
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();
}
}
在運作後,線上程中選擇main檢視:截圖如下所示:
接着選擇死循環方法,會看到,此循環一直在執行空循環,從堆棧中可以看到哪個類中的哪行代碼中停留,而且沒有看到線程歸還執行令牌的動作,會一直執行直到線程切換,這種等待會消耗較多的CPU資源。截圖如下所示;
劃橫線的地方就是具體哪個類中的哪個方法,在哪行出的問題,這個是說TestThread.java類中的第16行代碼,就是while(true);這行代碼。
而線程鎖等待部分,testLockThread線程在等待着lock對象的notify,notifyall方法,線程這時就是waiting狀态,在被喚醒前不會被配置設定執行時間。
轉載于:https://www.cnblogs.com/guopengxia0719/p/10618730.html