JVM調優監控常用工具

命令行工具

jps

(JVM Process Status Tool),類似於Linux的ps命令,用於列舉正在運行的虛擬機進程,並顯示虛擬機執行主類(main函數所在的類)名稱以及這些進程的本地虛擬機唯一ID(LVMID local virtual machine Identifier)。

 jps [-q] [-mlvV] [<hostid>]

-q:只輸出LVMID,省略主類的名稱。

-m:輸出虛擬機進程啓動時傳遞給主類main函數的參數

-l:輸出主類的全名,如果進程執行的是jar包,輸出jar路徑。

-v:輸出虛擬進程啓動時JVM參數。

jps -q
8424
5180
8268

jstat

(JVM Statics-Monitoring Tool) 是用於監視虛擬機各種運行狀態信息的命令行工具。它可以顯示本地或者遠程虛擬機進程中遠程虛擬機進程中的類加載、內存、垃圾收集、JIT編譯等運行數據。

  jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

vmid :如果是本地虛擬機進程,VMID和LVMID是一致的。

interval:表示查詢間隔。

count:表示查詢次數。

如果省略interval,count兩個參數,表示只查詢一次。

option具體現象和作用如下:

-class:監視類裝載、卸載數量、總空間以及類裝載所耗費的時間。
-compiler:輸出JIT編譯器編譯過的方法、耗時等信息。
-gc:監視java堆狀況,包括Eden區,survivor區,老年代,永久代等的容量,已用空間、GC時間合計等信息。
-gccapacity:監視內容和-gc基本相同,但輸出主要關注Java堆各個區域使用到的最大、最小空間。
-gccause:與gcutil功能一樣,但是會額外輸出導致上一次GC產生的原因。
-gcmetacapacity:顯示有關元空間大小的統計信息。
-gcnew:監視新生代GC狀況。
-gcnewcapacity:監視內容與-gcnew基本相同,輸出主要關注使用到的最大、最小空間。
-gcold:監視老年代的GC狀況。
-gcoldcapacity:監視內容與-gcold基本相同,輸出主要關注使用到的最大、最小空間。
-gcutil:監視內容和-gc基本相同,但輸出主要已使用空間佔總空間的百分比。
-printcompilation:輸出已經被JIT編譯的方法。

jstat -gc 5180 1000 10
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017
5120.0 5120.0 3825.2  0.0   33280.0  25547.9   87552.0      8.0     17536.0 17143.3 2176.0 2005.4      2    0.017   0      0.000    0.017

S0C:當前survivor space 0總容量(kB)
S1C:當前survivor space 1總容量(kB)
S0U:survivor space 0已使用容量(kB)
S1U:survivor space 1已使用容量(kB)
EC:當前eden space總容量(kB)
EU:eden space已使用容量(kB)
OC:當前old space總容量(kB)
OU:old space的已使用容量(kB)
MC:Metaspace 總容量(kB)
MU:Metacspace已使用容量(kB)
CCSC:壓縮類空間總容量(kB)
CCSU:已使用的壓縮類空間容量(kB)
YGC:Young generation GC次數
YGCT:Young generation GC總耗時
FGC:Full GC次數
FGCT:Full GC總耗時
GCT:GC總耗時

jinfo

(Configuration Info for Java) 實時地查看和調整虛擬機的各項參數。

格式

     jinfo [ option ] pid

     jinfo [ option ] executable core

     jinfo [ option ] [server-id@]remote-hostname-or-IP

參數說明

     pid  對應jvm的進程id

     executable core 產生core dump文件

     [server-id@]remote-hostname-or-IP  遠程的ip或者hostname,server-id標記服務的唯一性id

option

     no option   輸出全部的參數和系統屬性

     -flag  name  輸出對應名稱的參數

     -flag [+|-]name  開啓或者關閉對應名稱的參數

     -flag name=value  設定對應名稱的參數

     -flags  輸出全部的參數

     -sysprops  輸出系統屬性

jinfo 5180
Attaching to process ID 5180, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Java System Properties:

java.vendor = Oracle Corporation
preload.project.path = E:/Java/jvm
sun.java.launcher = SUN_STANDARD

...

jinfo -flags 5180
Attaching to process ID 5180, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=734003200 -XX:MaxNewSize=244318208 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:
+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=E:/Java/jvm -Dpreload.config.path=C:/Users/chuang.ji/.IntelliJIdea20
18.3/config/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=-2925694128290007609 -Dfile.encoding=GBK -Duser.langua
...

jmap

(Memory Map for Java) 命令用於生成堆轉儲快照(一般稱爲heapdump或dump文件)。另外它還可以查下finalize執行隊列、Java堆和永久代的詳細情況。不過jmap有一些功能在Windows平臺受限。

命令格式:

 jmap [option] <pid>     (to connect to running process)
 jmap [option] <executable <core>     (to connect to a core file)
 jmap [option] [server_id@]<remote server IP or hostname>     (to connect to remote debug server)

option可以是如下選項:

  <none>               to print same info as Solaris pmap
  -heap                to print java heap summary
  -histo[:live]        to print histogram of java object heap; if the "live"
                       suboption is specified, only count live objects
  -clstats             to print class loader statistics
  -finalizerinfo       to print information on objects awaiting finalization
  -dump:<dump-options> to dump java heap in hprof binary format
                       dump-options:
                         live         dump only live objects; if not specified,
                                      all objects in the heap are dumped.
                         format=b     binary format
                         file=<file>  dump heap to <file>
                       Example: jmap -dump:live,format=b,file=heap.bin <pid>
  -F                   force. Use with -dump:<dump-options> <pid> or -histo
                       to force a heap dump or histogram when <pid> does not
                       respond. The "live" suboption is not supported
                       in this mode.
  -h | -help           to print this help message
  -J<flag>             to pass <flag> directly to the runtime system

jstack

(Stack Trace for Java) 該命令用於生產虛擬機當前時刻的線程快照(threaddump)。線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導致的長時間等待等都是導致線程長時間停頓的常見原因。線程出現停頓的時候通過jstack來查看各個線程的調用堆棧,就可以知道沒有響應的線程到底在後臺做些什麼事情,或者等待着什麼資源。

命令格式:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

option選項:

    -F 當正常輸出的請求不被響應時,強制輸出線程堆棧。

    -l 除堆棧外,顯示鎖的附加信息。

    -m 打印java和native c/c++框架的所有棧信息

可視化工具

jconsole

(ava Monitoring and Management Console是一種基於JMX的可視化監視、管理工具。

啓動JConsole

通過JDK/bin目錄下的jconsole.exe啓動JConsole後,將會自動搜索本機運行的所有虛擬機進程,雙擊選擇其中一個進程即可開機監控,也可以使用下面的“遠程進程”功能來連接遠程服務器,對遠程虛擬機進行監控。

進入JConsole主界面後可以看到主界面包括“概覽”,“內存”,“線程”,“類”,“VM概要”,“MBean”。

“概覽”頁籤顯示的是整個虛擬機注意運行數據的概覽,其中包括“堆內存使用情況”、“線程”、“類”、“CPU事情情況”4種信息的曲線圖。這些曲線圖是後面“內存”、“線程”,“類”頁籤的信息彙總。

內存監控

“內存”頁籤相對於可視化的jstat命令,用於監視受收集器管理的虛擬機內存(Java堆和永久代)的變化趨勢。

運行下面的程序,同時利用JConsole進行監控:

import java.util.ArrayList;
import java.util.List;

public class jconsoledemo1 {
    static class OOMObject{
        public byte[] placeholder = new byte[64*1024];
    }

    public static void fillHeap(int num) throws InterruptedException{
        Thread.sleep(10000);
        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{
        fillHeap(1000);
    }
}

JVM的配置:-Xms100m -Xmx100m -XX:+UseSerialGC -XX:+PrintGCDetails

GC日誌

[GC (Allocation Failure) [DefNew: 27328K->3392K(30720K), 0.0264937 secs] 27328K->11669K(99008K), 0.0268020 secs] [Times: user=0.02 sys=0.00, real=0.03 secs] 
[GC (Allocation Failure) [DefNew: 30693K->3373K(30720K), 0.0381057 secs] 38970K->36132K(99008K), 0.0381500 secs] [Times: user=0.00 sys=0.03, real=0.04 secs] 
[GC (Allocation Failure) [DefNew: 30645K->3365K(30720K), 0.0270089 secs] 63404K->61645K(99008K), 0.0270596 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
[Full GC (System.gc()) [Tenured: 58279K->66334K(68288K), 0.0267295 secs] 67333K->66334K(99008K), [Metaspace: 9583K->9583K(1058816K)], 0.0267930 secs] [Times: user=0.02 sys=0.00, real=0.03 secs] 
Heap
 def new generation   total 30720K, used 476K [0x00000000f9c00000, 0x00000000fbd50000, 0x00000000fbd50000)
  eden space 27328K,   1% used [0x00000000f9c00000, 0x00000000f9c77328, 0x00000000fb6b0000)
  from space 3392K,   0% used [0x00000000fba00000, 0x00000000fba00000, 0x00000000fbd50000)
  to   space 3392K,   0% used [0x00000000fb6b0000, 0x00000000fb6b0000, 0x00000000fba00000)
 tenured generation   total 68288K, used 66334K [0x00000000fbd50000, 0x0000000100000000, 0x0000000100000000)
   the space 68288K,  97% used [0x00000000fbd50000, 0x00000000ffe17958, 0x00000000ffe17a00, 0x0000000100000000)
 Metaspace       used 9589K, capacity 9954K, committed 10240K, reserved 1058816K
  class space    used 1131K, capacity 1242K, committed 1280K, reserved 1048576K

線程監控

“線程”頁籤的功能相對於可視化的jstack命令,遇到線程停頓時可以使用這個頁籤進行監控分析。線程長時間停頓的主要原因有:等待外部資源(數據庫連接,網絡資源,設備資源等),死循環,鎖等待(活鎖和死鎖)

/**
 * 線程死鎖等待演示
 */
public class jconsoledemo3 {
    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);
                }
            }
        }
    }

    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的值,可能會導致死鎖。造成死鎖的原因是Integer.valueOf()方法基於減少對象創建次數和節省內存的考慮,[-128,127]之間的數字會被緩存,當valueOf()方法傳入參數在這個範圍之內,將之間返回緩存中的對象。也就是說,代碼中調用了200次Integer.valueOf()方法,一共返回了兩個不同的對象。假如在某個線程的兩個synchronized塊之間發生了一次線程切換,那就會出現線程A等着被線程B持有的Integer.valueOf(1),線程B又等着被線程A持有的Integer.valueOf(2),結果出現大家都跑不下去的情況。

 

線程-121等待一共被線程-192持有的Integer對象,而線程-192也等待一個被線程-121持有的Integer對象。這樣兩個線程就互相卡住,都不存在等待鎖釋放的希望。

VisualVM

VisualVM(All-in-One Jave Troubleshooting Tool)是隨JDK發佈的功能強大的運行監視和故障處理程序。它除了運行監視、故障處理外,還提供了許多其他方面的功能,如性能分析。和JProfiler,YourKit等專業Profiling工具相比,VisualVM還有一個很大的優點:不需要被監視的程序基於特殊agent運行,因此它對應用程序的實際性能影響很小,使得它可以直接應用在生產環境中。

VisualVm可以做到如下:

顯示虛擬機進程以及進程的配置、環境信息。

監視應用程序的 CPU、GC、堆、方法區以及線程的信息。

dump以及分析堆轉儲快照。

方法級的程序運行性能分析,找出被調用最多,運行時間最長的方法。

離線程序快照:收集程序的運行時配置、線程dump、內存dump等信息建立一個快照,可以將快照發送給開發者進行Bug反饋。

啓動VisualVM ,在目標應用程序中右擊,選擇"堆dump"或"線程dump",生成dump文件後,可以保存此文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章