JVM - 工欲善其事必先利其器之虚拟机工具(上)
文章目錄
- JVM - 工欲善其事必先利其器之虛擬機工具(上)
- 1.虛擬機工具的意義
- 2.jps(JVM Process Status Tool)
- 2.1 一說grep
- 2.2 jps是什么?
- 2.3 jps的使用
- 3.jstat(JVM Statistics Monitoring Tool)
- 3.1 jstat參數介紹
- 3.2 jstat的使用
- 3.2.1 -class
- 3.2.2 -gc
- 3.2.3 -gcnew/-gcold
- 3.2.4 -gccapacity
- 3.2.5 -gcnewcapacity/-gcoldcapacity/-gcmetacapacity
- 3.2.5 -gcutil
- 3.2.6 -gccause
- 3.2.7 -compiler
- 3.2.7 -printcompilation
- 3.2.8 -class
- 4.jinfo(Configuration Info for Java)
- 5.jmap(Memory Map for Java)
- 5.1 jmap是什么?
- 5.2 jmap常用指令
- 5.2.1 -heap
- 5.2.2 -histo
- 5.2.3 -dump
- 5.3 安利一個JVM可視化分析網站-PerfMa
- 5.jhat(JVM Heap Analysis Tool)
- 6.jstack(Stack Trace for Java)
- 6.1 jstack是什么?
- 6.2 jstack的使用
- 6.3 線程狀態
- 7.總結
JVM - 工欲善其事必先利其器之虛擬機工具(上)
1.虛擬機工具的意義
?如果小伙伴們從第一章看到現在,那么我相信大家對JVM已經有了一定認識了,但是我們也需要學會武裝自己才能夠徹底征服JVM,虛擬機工具自然而然就是最好的武器。
?
?當我們給一個程序系統定位JVM相關問題時,我們對知識的理解就像游戲里我們對角色的的理解;我們處理問題的經驗就像我們角色的能力值;數據就像是地圖上所能利用的資源;而工具就是我們通關所運用的手段。
?
?而這里面的數據就包括:運行日志、異常堆棧、GC日志、線程快照、堆轉儲快照等。如果能夠合理并且熟練地使用這些虛擬機工具,可以對數據進行快速分析并且提高定位問題解決問題的效率。這里我們就對一些常用的虛擬機工具進行介紹,讓自己變得更加強大。
2.jps(JVM Process Status Tool)
2.1 一說grep
?大家對Linux應該都不會默認,我們經常會使用一個命令就是ps -ef|grep。
?
?grep命令主要就是用于查找,|是管道命令可以使ps和grep同時執行。ps也是Linux中最常用而且非常強大的查看進程命令,而grep則是一種十分強大的文本搜索命令,還可以使用正則表達式將匹配的文本進行輸出。假如我們需要查找正在運行的java程序,則可以使用ps -ef|grep java。
2.2 jps是什么?
?在介紹JPS前我們先看一樣東西,就是我們熟悉的JDK。我們找到JDK安裝路徑找到bin目錄,可以看到這里面有很多應用程序,這其中就包括jps、jmap等。
?再找到lib目錄下tools.jar,打開之后可以看到這里面其實就包含了我們所看到jps等命令的源碼,所以JDK本身其實就提供了許多虛擬機相關的工具來方便我們發現、分析以及解決虛擬機的問題。
?jps就是其中比較典型的JVM工具,我們會發現名稱和ps命令很相像,而其實功能也與ps命令相似。我們可以通過jps命令顯示出虛擬機執行主類(Main Class)名稱以及其進程對應的本地虛擬機標識(Local Virtual Machine Identifier-LVMID),雖然功能比較單一但卻是使用頻率最高的工具。
2.3 jps的使用
?jps命令的使用很簡單,這里我們隨手啟動一個之前的項目,分別介紹一下幾個參數的作用。
jps -l
?輸出程序主類全名,若進程執行的是Jar包則輸出Jar包路徑
jps -m
?輸出虛擬機進程啟動時傳遞給主類main()函數的參數。
jps -v
?輸出虛擬機進程JVM參數,這里我們可以看到我們之前示例自己所設置的JVM參數。這個命令使用起來也很簡單,相信大家也很熟悉就不過多介紹了。
3.jstat(JVM Statistics Monitoring Tool)
?jstat命令也是我們JDK包中自帶的小工具,主要用于監視虛擬機各種運行狀態信息。可以顯示Java應用程序運行時的類裝載、內存使用、垃圾收集、JIT編譯等運行狀況。若不適用GUI圖形界面工具進的話,那么它就是定位虛擬機性能問題的首選工具。
3.1 jstat參數介紹
?這里我們輸入jstat -help查看一下有哪些參數可以供我們使用,另外提一句當大家不知道其他命令如何使用時,一般直接輸入命令例如jstat或者jstat -help都會提示相關用法介紹。
?上面我們對基本的參數做了一個簡單介紹,這里我們再通過jstat -options來看看options參數能夠怎么選擇,接下來我們通過實際情況給大家分別介紹下每個參數選項的用法。
3.2 jstat的使用
3.2.1 -class
?顯示ClassLoad的裝載、卸載數量以及所占空間和耗費時間,這里8468就是我們通過jps獲取的進程pid,250表示250ms執行一次,10表示總共執行次數。
3.2.2 -gc
?顯示應用程序GC相關堆信息,主要包括Eden區、Survivor區、老年代、永久代等容量使用情況以及GC時間消耗等信息。
3.2.3 -gcnew/-gcold
?當然我們也可以通過-gcnew和-gcold單獨查看新生代或者老年代的GC信息。
3.2.4 -gccapacity
?顯示各分代容量及使用情況。
3.2.5 -gcnewcapacity/-gcoldcapacity/-gcmetacapacity
?這里我們也可以通過-gcnewcapacity、-gcoldcapacity、-gcmetacapacity分別查看年輕代、老年代以及元空間容量以及使用情況。
3.2.5 -gcutil
?主要用于顯示GC統計信息。
3.2.6 -gccause
?內容和-gcutil大致一樣,顯示GC相關信息,會額外顯示最后一次或正在進行的GC原因。
3.2.7 -compiler
?顯示JIT編譯相關信息。
3.2.7 -printcompilation
?顯示已經被JIT編譯的方法信息。
3.2.8 -class
?顯示加載Class相關信息。
4.jinfo(Configuration Info for Java)
?jinfo命令的作用主要是實時查看虛擬機各項參數。我們知道使用jps -v命令可以查看虛擬機啟動時顯示指定的參數列表,但是我們想要知道除了顯示指定的其他參數要如何做呢?jinfo就給我們提供了這個功能。
?這里我們通過jinfo pid可以看到經過一個短時間的等待后,會將很多很多信息輸出給我們,這里面就包括各種應用環境配置、JVM參數配置等,小伙伴們可以自己動手去執行看看。如果大家想要查看程序詳細的配置,那么jinfo命令是你的不二選擇。
5.jmap(Memory Map for Java)
5.1 jmap是什么?
?jmap命令主要可以用于生成堆轉儲快照。和jinfo命令一樣,如果大家在windows平臺執行某些命令失效是正常的,有些功能在Windows下是不支持的。
?
?除了可以獲取dump文件,我們還能夠通過jmap查詢到堆中各代空間使用率等情況,并且可以查看到每種類的實例、空間占用等信息。
?
?另外我們除了jmap生成堆轉儲快照之外,還可以通過JVM啟動參數中設置-XX:+HeapDumpOnOutOfMemoryError讓程序在OOM后自動生成dump文件。然后通過分析dump文件去解決相關問題。
5.2 jmap常用指令
5.2.1 -heap
?顯示堆中詳細信息,包括參數配置、使用垃圾收集器、各代空間使用等情況。
5.2.2 -histo
?-histo命令是我們上章使用過的一個命令,大家可能會有一點印象。當時我們通過jmap -histo:live 2772>jmap_histo.log命令將堆中存活對象統計信息輸出到了日志文件中用于分析開啟逃逸分析的效果。這里我們也可以通過jmap -histo pid直接去查看堆中對象信息,另外如果因為信息太多的我們可以通過jmap -histo pid|more自己去分頁查看。
?
?這里面主要包括類、實例數量、所占字節量。另外我們可以看到其中有幾個比較特殊的標識:【I、【B、【C,這幾個其實就是我們所熟悉的int、byte、char類型數據。
5.2.3 -dump
?dump命令主要作用就是用來生成堆轉儲快照,可供我們對程序運行情況進行分析。主要格式就是jmap -dump:format=b,file=xxx pid
5.3 安利一個JVM可視化分析網站-PerfMa
?我們在之前介紹了很多例如GC日志、JVM啟動參數、堆轉儲快照等,那么這些日志怎么分析、參數怎么設置呢?
?
?除了我們通過自己的經驗之外,這里我給大家安利一個網站【PerfMa】。
?這個網站提供了很多可視化分析的界面,并且還能夠通過你不同機器的硬件配置情況制定不同的JVM啟動參數。這里我們就用我們上面dump下的堆轉儲快照為例。
?這里導入dump文件也十分方便,直接拖拽即可。
?大家可以看到分析生成后的可視化界面真的十分強大,堆內存使用情況、GC ROOT個數、線程個數以及每個類的實例個數、所占容量大小甚至類加載器、每個對象信息都能夠看到,還支持一些常用的條件搜索可以定位到我們需要精準查找的內容。
?
?大家可以自己使用感受一下他的強大。如果我們自身已經對JVM有了一定的了解,那么這些強大的可視化分析工具就不是阻礙我們成長的羈絆而是助力器。
5.jhat(JVM Heap Analysis Tool)
?當然如果我們沒有上面介紹的可視化分析工具的話,我們要如何去分析dump文件呢?答案就是jhat命令,這個命令經常和jmap搭配使用,主要作用和上面類似就是用于分析堆轉儲快照。
?
?jhat可以將dump文件進行分析后通過瀏覽器去進行查看,但是需要注意的是jhat分析工作是一個耗時且對硬件資源有消耗的過程,整個分析功能也比較簡陋,不過我們這里也來看看他到底是會怎樣進行分析。
?
?我們使用上面的dump文件。
?如果顯示上面這樣就是啟動成功了,我們可以看到他提示默認端口為7000,這里我們嘗試進行訪問。
?我們可以看到jhat會通過分析dump文件幫我們生成一個這樣的界面,這里面也包括一些堆使用情況,這些數據大家是不是十分熟悉。另外jhat還提供了一個OQL查詢功能。
?這里我們可以通過OQL語句去按照條件查詢對象情況,如果大家想要嘗試的話可以看看這里也提供了一個OQL HELP,不過如果我們已經有了更強大的工具的話可能就很少會去使用這些命令了。
6.jstack(Stack Trace for Java)
6.1 jstack是什么?
?我們上面講的那么多命令,會發現很多都是和堆內存信息有關的信息,那么在我們項目中除了堆中內存管理還有什么是我們經常會碰到并且總是難以下手的呢?沒錯,就是線程。
?
jstack命令就是用于生成JVM當前時刻的線程快照(threaddump)。線程快照其實就是當前JVM中每條線程正在執行的方法堆棧的一個集合。
?
?當線程死鎖、死循環、請求外部資源長時間等待時都可能造成線程長時間停頓,我們生成線程快照的目的就是為了定位并解決這些問題。當線程出現停頓時我們可以通過jstack來查看各線程調用堆棧鏈,從而分析線程當前狀態以及造成問題的原因。
6.2 jstack的使用
?同樣我們啟動開始的程序,通過jps命令獲取進程PID。這里我們通過jstack -l 4728命令就會輸出當前時刻線程快照了,我們可以看到這里面包括每個線程的狀態、標識信息、堆棧調用鏈等,還是很詳細的,我們可以通過這些信息去分析線程停頓造成的原因從而找到解決方案。下面我們來一個示例看看當我們線程死鎖了會是怎樣的。(線程死鎖是指由于兩個或者多個線程互相持有對方所需要的資源,導致這些線程處于等待狀態,無法前往執行)
public class DeadLock {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(Thread.currentThread().getName() + "get lock1");Thread.sleep(3000);}catch (Exception e){e.printStackTrace();}synchronized (lock2){System.out.println(Thread.currentThread().getName() + "get lock2");}}}, "線程1").start();new Thread(() -> {synchronized (lock2){try {System.out.println(Thread.currentThread().getName() + "get lock2");Thread.sleep(3000);}catch (Exception e){e.printStackTrace();}synchronized (lock1){System.out.println(Thread.currentThread().getName() + "get lock1");}}}, "線程2").start();}}?大家應該都知道線程是什么,就是兩個或多個線程互相持有對方所需要的資源,導致這些線程都處于一個等待狀態,從而造成線程死鎖。
?
?我們這里用這個簡單的例子來模擬一下線程死鎖,我們啟動之后會發現應用處于等待狀態,這個時候我們通過開始的命令jstack -l pid。
?這里可以看到他幫我們分析出了發現了一處死鎖,并且把相關的線程信息和方法調用堆棧位置都給我們標記出來了,同時還顯示出了死鎖造成的原因是由于等待哪一個鎖造成的。通過線程快照我們可以很快地定位線程停頓的原因,大家可以自己動手去試一試感受一下。
6.3 線程狀態
?這里提到線程那就大家一起簡單復習一下線程有哪幾種狀態。
?
?這里我們主要就是稍微理解一下WAITING 和BLOCKED,前者是主動顯示申請阻塞,后者屬于被動阻塞。另外一個就是WAITING和TIMED_WAITING,前者可以無限期等待而后者有一個時間限制。
7.總結
?這一章我們主要介紹了JDK自帶工具包中一些關于JVM應用程序相關的命令,可以幫助我們去查看應用程序的一些堆存儲狀態、應用程序信息、線程狀態等,讓我們可以在有問題或者需要時對其運行狀況進行了解。
?
?隨著JAVA的發展,也有越來越多更成熟更好用的可視化工具可以幫助我們對應用程序進行分析,下一章我們就來對這些可視化工具進行一個了解和使用。
總結
以上是生活随笔為你收集整理的JVM - 工欲善其事必先利其器之虚拟机工具(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Shopee开店首站有哪些站点?虾皮入驻
- 下一篇: 工欲善其事必先利其器——AWS认证是你最