JVM調優工具使用手冊

2022-11-10 18:00:49

​ 作為Java開發人員,我們肯定知道JDK的bin目錄下有"java.exe"、"javac.exe"這兩個命令工具,這也是我們平時用得最多的工具。但其實bin目錄下還有很多工具,這些工具可以幫助我們進行JVM的調優,幫我們定位找出應用程式執行中產生的問題。下面我們來看看其中一些調優工具。

前置啟動程式

​ 先啟動一個web應用程式,然後用各種JDK自帶命令優化應用。

jps

jps					

​ 用jps檢視應用進行ID

jinfo

jinfo -flags 92604

​ 此命令可以實時檢視和調整虛擬機器器各項引數。

jmap

​ 此命令可以用來檢視記憶體資訊,範例個數以及佔用大小,還可以生成堆轉儲快照。

jmap -histo 14660  #檢視歷史生成的範例
jmap -histo:live 14660  #檢視當前存活的範例,執行過程中可能會觸發一次full gc

開啟log.txt,內容如下:

  • num:序號
  • instances:範例數量
  • bytes:佔用空間大小
  • class name:類名稱,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]

堆資訊

​ 可以檢視當前應用的堆具體設定、使用資訊。

jmap -heap 92604

轉儲堆記憶體dump

jmap -dump:format=b,file=web.hprof 92604

也可以設定記憶體溢位自動匯出dump檔案(記憶體很大的時候,可能會導不出來)

  1. -XX:+HeapDumpOnOutOfMemoryError
  2. -XX:HeapDumpPath=./ (路徑)

範例程式碼:

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

jvisualvm

​ 該命令可以開啟一個視覺化介面,監視當前執行應用程式、dump檔案進行故障分析等功能。

​ 匯入上面範例程式碼執行後產生的hprof檔案,可以看到User物件範例數名列前茅。

jstack

​ 此命令可以用來跟蹤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自動檢測到死鎖。

找出佔用cpu最高的執行緒堆疊資訊

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命令可以檢視堆記憶體各部分的使用量,以及載入類的數量。命令的格式如下:

jstat [-命令選項] [vmid] [間隔時間(毫秒)] [查詢次數]

注意:使用的jdk版本是jdk8

整體GC壓力情況(常用)

jstat -gc 103784 2000 1000

​ 可以評估程式記憶體使用及GC壓力整體情況,監控gc,每2000ms列印輸出一次,輸出1000次。

  • S0C:第一個倖存區的大小,單位KB
  • S1C:第二個倖存區的大小
  • S0U:第一個倖存區的使用大小
  • S1U:第二個倖存區的使用大小
  • EC:伊甸園區的大小
  • EU:伊甸園區的使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • MC:方法區大小(元空間)
  • MU:方法區使用大小
  • CCSC:壓縮類空間大小
  • CCSU:壓縮類空間使用大小
  • YGC:年輕代垃圾回收次數
  • YGCT:年輕代垃圾回收消耗時間,單位s
  • FGC:老年代垃圾回收次數
  • FGCT:老年代垃圾回收消耗時間,單位s
  • GCT:垃圾回收消耗總時間,單位s

堆記憶體統計

jstat -gccapacity 103784

  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:當前新生代容量
  • S0C:第一個倖存區大小
  • S1C:第二個倖存區的大小
  • EC:伊甸園區的大小
  • OGCMN:老年代最小容量
  • OGCMX:老年代最大容量
  • OGC:當前老年代大小
  • OC:當前老年代大小
  • MCMN:最小後設資料容量
  • MCMX:最大後設資料容量
  • MC:當前後設資料空間大小
  • CCSMN:最小壓縮類空間大小
  • CCSMX:最大壓縮類空間大小
  • CCSC:當前壓縮類空間大小
  • YGC:年輕代gc次數
  • FGC:老年代GC次數

新生代垃圾回收統計

jstat -gcnew 103784

新生代記憶體統計

jstat -gcnewcapacity 103784

  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:當前新生代容量
  • S0CMX:最大幸存1區大小
  • S0C:當前倖存1區大小
  • S1CMX:最大幸存2區大小
  • S1C:當前倖存2區大小
  • ECMX:最大伊甸園區大小
  • EC:當前伊甸園區大小
  • YGC:年輕代垃圾回收次數
  • FGC:老年代回收次數

老年代垃圾回收統計

jstat -gcold 103784

老年代記憶體統計

jstat -gcoldcapacity 103784

後設資料空間統計

jstat -gcmetacapacity 103784

  • MCMN:最小後設資料容量
  • MCMX:最大後設資料容量
  • MC:當前後設資料空間大小
  • CCSMN:最小壓縮類空間大小
  • CCSMX:最大壓縮類空間大小
  • CCSC:當前壓縮類空間大小
  • YGC:年輕代垃圾回收次數
  • FGC:老年代垃圾回收次數
  • FGCT:老年代垃圾回收消耗時間
  • GCT:垃圾回收消耗總時間

總結

​ 上面介紹到的各個命令,都是JDK提供給我們的最基礎的調優工具,如果還有功能更好的,那也是基於上面的基礎功能進行開發封裝。所以我們只要理解會用上面的各個命令,調優也不是什麼問題。