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