作為Java開發人員,我們肯定知道JDK的bin目錄下有"java.exe"、"javac.exe"這兩個命令工具,這也是我們平時用得最多的工具。但其實bin目錄下還有很多工具,這些工具可以幫助我們進行JVM的調優,幫我們定位找出應用程式執行中產生的問題。下面我們來看看其中一些調優工具。
先啟動一個web應用程式,然後用各種JDK自帶命令優化應用。
jps
用jps檢視應用進行ID
jinfo -flags 92604
此命令可以實時檢視和調整虛擬機器器各項引數。
此命令可以用來檢視記憶體資訊,範例個數以及佔用大小,還可以生成堆轉儲快照。
jmap -histo 14660 #檢視歷史生成的範例
jmap -histo:live 14660 #檢視當前存活的範例,執行過程中可能會觸發一次full gc
開啟log.txt,內容如下:
可以檢視當前應用的堆具體設定、使用資訊。
jmap -heap 92604
jmap -dump:format=b,file=web.hprof 92604
也可以設定記憶體溢位自動匯出dump檔案(記憶體很大的時候,可能會導不出來)
範例程式碼:
public class OOMTest {
public static List<Object> list = new ArrayList<>();
// JVM設定
// -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\jvm.dump
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
int i = 0;
int j = 0;
while (true) {
list.add(new User(i++, UUID.randomUUID().toString()));
}
}
}
jvisualvm
該命令可以開啟一個視覺化介面,監視當前執行應用程式、dump檔案進行故障分析等功能。
匯入上面範例程式碼執行後產生的hprof檔案,可以看到User物件範例數名列前茅。
此命令可以用來跟蹤Java堆疊資訊。用於生成虛擬機器器當前試課的執行緒快照。快照可以定位執行緒出現長時間停頓的原因,如執行緒間死鎖、死迴圈、請求外部資源導致的長時間等待等都是導致執行緒長時間停頓的常見原因。
public class DeadLockTest {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
try {
System.out.println("thread1 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock2) {
System.out.println("thread1 end");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
try {
System.out.println("thread2 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
synchronized (lock1) {
System.out.println("thread2 end");
}
}
}).start();
System.out.println("main thread end");
}
}
jstack 100516
"Thread-1":執行緒名
prio=5: java執行緒優先順序
os_prio:作業系統執行緒優先順序
nid=0x18688 執行緒對應的本地執行緒標識nid
java.lang.Thread.State: BLOCKED 執行緒狀態
還可以用jvisualvm自動檢測到死鎖。
public class Math {
public static final int initData = 666;
public static User user = new User();
public int compute() { //一個方法對應一塊棧幀記憶體區域
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
public static void main(String[] args) {
Math math = new Math();
while (true){
math.compute();
}
}
}
1,使用命令top -p ,顯示你的java程序的記憶體情況,pid是你的java程序號,比如18963
2,按H,獲取每個執行緒的記憶體情況
3,找到記憶體和cpu佔用最高的執行緒tid,比如18964
4,轉為十六進位製得到 0x4a14,此為執行緒id的十六進位製表示
5,執行 jstack 18963|grep -A 10 4a14,得到執行緒堆疊資訊中 4cd0 這個執行緒所在行的後面10行,從堆疊中可以發現導致cpu飆高的呼叫方法
6,檢視對應的堆疊資訊找出可能存在問題的程式碼
jstat命令可以檢視堆記憶體各部分的使用量,以及載入類的數量。命令的格式如下:
jstat [-命令選項] [vmid] [間隔時間(毫秒)] [查詢次數]
注意:使用的jdk版本是jdk8
jstat -gc 103784 2000 1000
可以評估程式記憶體使用及GC壓力整體情況,監控gc,每2000ms列印輸出一次,輸出1000次。
jstat -gccapacity 103784
jstat -gcnew 103784
jstat -gcnewcapacity 103784
jstat -gcold 103784
jstat -gcoldcapacity 103784
jstat -gcmetacapacity 103784
上面介紹到的各個命令,都是JDK提供給我們的最基礎的調優工具,如果還有功能更好的,那也是基於上面的基礎功能進行開發封裝。所以我們只要理解會用上面的各個命令,調優也不是什麼問題。