一设褐、JDK的命令行工具
所有的命令行工具都在bin
目錄中颠蕴。Sun JDK
監(jiān)控和故障處理工具如下:
名稱 | 主要作用 |
---|---|
jps |
JVM Process Status Tool 拉鹃,顯示指定系統(tǒng)內(nèi)所有的HotSpot 虛擬機(jī)進(jìn)程 |
jstat |
JVM Statistics Monitoring Tool 扰藕,用于收集HotSpot 虛擬機(jī)各方面的運(yùn)行數(shù)據(jù) |
jinfo |
Configuration Info for Java 倘待,顯示虛擬機(jī)配置信息 |
jmap |
Memory Map for Java 胀屿,生成虛擬機(jī)的內(nèi)存轉(zhuǎn)儲快照(headdump 文件) |
jhat |
JVM Heap Dump Browser ,用于分析headdump 文件桅滋,它會建立一個HTTP/HTML 服務(wù)器绑青,讓用戶可以在瀏覽器上查看分析結(jié)果 |
jstack |
Stack Trace for Java ,顯示虛擬機(jī)的線程快照 |
1.1 jps:虛擬機(jī)進(jìn)程狀況工具
此工具可以列出正在運(yùn)行的虛擬機(jī)進(jìn)程锥惋,并顯示虛擬機(jī)執(zhí)行主類(Main Class, main()
函數(shù)所在的類)名稱以及這些進(jìn)程的本地虛擬機(jī)唯一ID(Local Virtual Machine Identifier开伏,LVMID)
膀跌。其他的JDK
工具大多需要輸入它查詢到的LVMID
來確定要監(jiān)控的是哪一個虛擬機(jī)進(jìn)程。對于本地虛擬機(jī)進(jìn)程來說固灵,LVMID
與操作系統(tǒng)的進(jìn)程ID(Process Identifier捅伤,PID)
是一致的,使用windows
的任務(wù)管理器或UNIX
的ps
命令也可以查詢到虛擬機(jī)進(jìn)程的LVMID
巫玻,但如果同時啟動了多個虛擬機(jī)進(jìn)程丛忆,無法根據(jù)進(jìn)程名稱定位時,那就只能依賴此命令顯示主類的功能才能區(qū)分了仍秤。命令格式如下:
jps [ options ] [ hostid ]
其主要選項(xiàng)如下:
選項(xiàng) | 作用 |
---|---|
-q |
只輸出LVMID 熄诡,省略主類的名稱 |
-m |
輸出虛擬機(jī)進(jìn)程啟動時傳遞給主類main() 函數(shù)的參數(shù) |
-l |
輸出主類的全名,如果進(jìn)程執(zhí)行的是Jar 包诗力,輸出Jar 路徑 |
-v |
輸出虛擬機(jī)進(jìn)程啟動時JVM 參數(shù) |
1.2 jstat:虛擬機(jī)統(tǒng)計信息監(jiān)視工具
此工具用于監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具凰浮。它可以顯示本地或者遠(yuǎn)程虛擬機(jī)進(jìn)程中的類裝載、內(nèi)存、垃圾收集袜茧、JIT
編譯等運(yùn)行數(shù)據(jù)菜拓。其命令格式為:
jstat [ option vmid [ interval [ s|ms ] [ count ] ] ]
說明:如果是本地虛擬機(jī)進(jìn)程,VMID
與LVMID
是一致的笛厦,如果是遠(yuǎn)程虛擬機(jī)進(jìn)程纳鼎,那VMID
的格式應(yīng)當(dāng)是:
[ protocol: ][ // ] lvmid [ @hostname [ :port ] / servername ]
其中interval
和count
代表查詢間隔和次數(shù),如果省略這兩個參數(shù)裳凸,說明只查詢一次喷橙。假設(shè)需要250ms
查詢一次進(jìn)程2764
垃圾收集狀況,一共查詢20
次登舞,那命令應(yīng)該是:
jstat -gc 2764 250 20
選項(xiàng)option
代表著用戶希望查詢的虛擬機(jī)信息贰逾,主要分為三類:類裝載、垃圾收集菠秒、運(yùn)行期編譯狀況疙剑,具體選項(xiàng)及作用如下:
選項(xiàng) | 作用 |
---|---|
-class |
監(jiān)視類裝載、卸載數(shù)量践叠、總空間以及類裝載所耗費(fèi)的時間 |
-gc |
監(jiān)視Java 堆狀況言缤,包括Eden 區(qū)、兩個survivor 區(qū)禁灼、老年代管挟、永久代等的容量、已用空間弄捕、GC 時間合計等信息 |
-gccapacity |
監(jiān)視內(nèi)容與-gc 基本相同僻孝,但輸出主要關(guān)注Java 堆各個區(qū)域使用到的最大、最小空間 |
-gcutil |
監(jiān)視內(nèi)容與-gc 基本相同守谓,但輸出主要關(guān)注已使用空間占總空間的百分比 |
-gccause |
與-gcutil 功能一樣穿铆,但是會額外輸出導(dǎo)致上一次GC 產(chǎn)生的原因 |
-gcnew |
監(jiān)視新生代GC 狀況 |
-gcnewcapacity |
監(jiān)視內(nèi)容與-gcnew 基本相同,輸出主要關(guān)注使用到的最大斋荞、最小空間 |
-gcold |
監(jiān)視老年代GC 狀況 |
-gcoldcapactiy |
監(jiān)視內(nèi)容與-gcold 基本相同荞雏,輸出主要關(guān)注使用到的最大、最小空間 |
-gcpermcapacity |
輸出永久代使用到的最大平酿、最小空間 |
-compiler |
輸出JIT 編譯器編譯過的方法凤优、耗時等信息 |
-printcompilation |
輸出已經(jīng)被JIT 編譯的方法 |
下面通過一個例子簡單了解一下:
說明:這臺服務(wù)器的新生代
Eden
區(qū)(E
,表示Eden
)使用了6.2%
的空間蜈彼,兩個survivor
區(qū)(S0筑辨、S1
,表示survivor0柳刮、survivor1
)里面都是空的挖垛,老年代(O
痒钝,表示Old
)和永久代(P
,表示Permanent
)則分別使用了41.42%
和47.20%
的空間痢毒。程序運(yùn)行以來共發(fā)生Minor GC
(YGC
送矩,表示Young GC
)16
次,總耗時0.105s
哪替,發(fā)生Full GC
(FGC
栋荸,表示Full GC
)三次,Full GC
總耗時(FGCT
凭舶,表示Full GC Time
)為0.472s
晌块,所有GC
總耗時(GCT
,表示GC Time
)為0.577s
帅霜。
1.3 jinfo:Java配置信息工具
此工具是實(shí)時地查看和調(diào)整虛擬機(jī)各項(xiàng)參數(shù)匆背。使用jps
命令的-v
參數(shù)可以查看虛擬機(jī)啟動時顯式指定的參數(shù)列表,但如果想知道未被顯式指定的參數(shù)的系統(tǒng)默認(rèn)值身冀,除了去找資料外钝尸,就只能使用jinfo
的-flag
選項(xiàng)進(jìn)行查詢了(如果只限于JDK1.6
或以上版本,則使用java -XX:+PrintFlagsFinal
查看參數(shù)默認(rèn)值也是一個很好的選擇)搂根,jinfo
還可以使用-sysprops
選項(xiàng)把虛擬機(jī)進(jìn)程的Sytem.getProperties()
的內(nèi)容打印出來珍促,還有在運(yùn)行期修改參數(shù)的能力,可以使用-flag[+|-] name
或-flag name=value
修改一部分運(yùn)行期可寫的虛擬機(jī)參數(shù)值剩愧。在windows
中有較大限制猪叙,只提供了最基本的-flag
選項(xiàng)。其命令格式如下:
jinfo [ option ] pid
1.4 jmap:Java內(nèi)存映像工具
此命令用于生成堆轉(zhuǎn)儲快照(一般稱為headdump
或dump
文件)仁卷。如果不實(shí)用此命令穴翩,要想獲取Java
堆轉(zhuǎn)儲快照,可以使用之前提到的暴力手段五督,即使用-XX:+HeadDumpOnOutOfMemoryError
參數(shù)藏否,可以讓虛擬機(jī)在OOM
異常出現(xiàn)之后自動生成dump
文件,通過-XX:+HeadDumpOnCtrlBreak
參數(shù)則可以使用[Ctrl]+[Break]
鍵讓虛擬機(jī)生成dump
文件充包,又或者在Linux
中使用Kill -3
命令拿到dump
文件。當(dāng)然遥椿,此命令的作用不僅僅是為了獲取dump
文件基矮,它還可以查詢finalize
執(zhí)行隊列、Java
堆和永久代的詳細(xì)信息冠场,如空間使用率家浇、當(dāng)前用的是哪種收集器等。其功能在windows
中受限碴裙,除了生成dump
文件的-dump
選項(xiàng)和用于查看每個類的實(shí)例钢悲、空間占用統(tǒng)計的-histo
選項(xiàng)在所有操作系統(tǒng)都提供之外点额,其余選項(xiàng)都智能在Linux/Solaris
下使用。其命令格式:
jmap [ option ] vmid
主要選項(xiàng)如下:
選項(xiàng) | 作用 |
---|---|
-dump |
生成Java 堆轉(zhuǎn)儲快照莺琳。格式為:-dump:[live, ]format=b, file=<filename> , 其中live 子參數(shù)說明是否只dump 出存活的對象 |
-finalizerinfo |
顯示在F-Queue 中等待Finalizer 線程執(zhí)行finalizer 方法的對象还棱。只在Linux/Solaris 平臺有效 |
-heap |
顯示Java 堆詳細(xì)信息,如使用哪種回收期惭等、參數(shù)配置珍手、分代狀況等。只在Linux/Solaris 平臺有效 |
-histo |
顯示堆中對象統(tǒng)計信息辞做,包括類琳要、實(shí)例數(shù)量、合計容量 |
-permstat |
以ClassLoader 為統(tǒng)計口徑顯示永久代內(nèi)存狀態(tài)秤茅。只在Linux/Solaris 平臺有效 |
-F |
當(dāng)虛擬機(jī)進(jìn)程對-dump 選項(xiàng)沒有響應(yīng)時稚补,可使用這個選項(xiàng)強(qiáng)制生成dump 快照。只在Linux/Solaris 平臺有效 |
例如:(3500
是LVMID
)
1.5 jhat:虛擬機(jī)堆轉(zhuǎn)儲快照分析工具
此命令和jmap
搭配使用框喳,來分析jmap
生成的堆轉(zhuǎn)儲快照孔厉。其內(nèi)置一個微型的HTTP/HTML
服務(wù)器,生成dump
文件的分析結(jié)果后帖努,可以在瀏覽器中查看撰豺。一般不會使用此命令來分析dump
文件,因?yàn)橐皇且话悴粫诓渴饝?yīng)用的服務(wù)器上直接分析dump
文件(太耗資源)拼余,而是此工具功能相對較為簡陋污桦,可以使用后面講到的VisualVM
工具替代。
1.6 jstack:Java堆棧跟蹤工具
此命令用于生成虛擬機(jī)當(dāng)前時刻的線程快照(一般稱為threaddump
或者javacore
文件)匙监。線程快照就是當(dāng)前虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合凡橱,生成線程快照的主要目的是定位線程出現(xiàn)長時間停頓的原因,如線程間死鎖亭姥、死循環(huán)稼钩、請求外部資源導(dǎo)致的長時間等待等都是導(dǎo)致線程長時間停頓的常見原因。線程出現(xiàn)停頓的時候通過此命令來查看各個線程的調(diào)用堆棧达罗,就可以知道沒有響應(yīng)的線程到底在后臺做什么坝撑,或等待什么資源。其格式為:
jstack [ option ] vmid
主要選項(xiàng)如下:
選項(xiàng) | 作用 |
---|---|
-F |
當(dāng)正常輸出的請求不被響應(yīng)時粮揉,強(qiáng)制輸出線程堆棧 |
-l |
除堆棧外巡李,顯示關(guān)于鎖的附加信息 |
-m |
如果調(diào)用到本地方法的話,可以顯示C/C++ 的堆棧 |
在JDK1.5中扶认,java.lang.Thread類新增了一個getAllStackTraces()方法用于獲取虛擬機(jī)中所有線程的StackTraceElement對象侨拦。使用此方法通過幾行簡單的代碼就可以完成jstack的大部分功能,在實(shí)際項(xiàng)目中不妨調(diào)用此方法做個管理員頁面辐宾,隨時查看線程堆棧狱从。
1.7 HSDIS:JIT生成代碼反匯編
隨著技術(shù)的發(fā)展膨蛮,高性能虛擬機(jī)真正的細(xì)節(jié)實(shí)現(xiàn)方式逐漸成了虛擬機(jī)實(shí)現(xiàn)的“概念模型”——即實(shí)現(xiàn)智能保證規(guī)范描述等效〖狙校基于此原因敞葛,在分析程序的執(zhí)行語義問題(虛擬機(jī)做了什么)時,在字節(jié)碼層面上分析完全可行训貌,但分析程序的執(zhí)行行為問題(虛擬機(jī)是怎樣做的制肮、性能如何)時,在字節(jié)碼層面上分析居沒有什么意義了递沪,需要通過其他方式解決豺鼻。
HSDIS
是官方對劍的HotSpot
虛擬機(jī)JIT
編譯代碼的反匯編插件,它包含在HotSpot
虛擬機(jī)的源碼之中款慨,但沒有提供編譯后的程序儒飒。其作用是讓HotSpot
的-XX:+PrintAssembly
指令調(diào)用它來把動態(tài)生成的本地代碼還原為匯編輸出,同時還生成大量非常有價值的注釋檩奠,這樣我們就可以通過輸出的代碼來分析問題桩了。注意,如果使用的Debug
或FastDebug
版的HotSpot
埠戳,那可以直接通過-XX:+PrintAssembly
指令使用插件井誉;如果使用的是Product
版的HotSpot
,那還要額外加入一個-XX:+UnlockDiagnosticVMOptions
參數(shù)整胃。
例如:測試代碼
public class Bar{
int a = 1;
static int b = 2;
public int sum(int c ){
return a + b + c;
}
public static void main(String[] args){
new Bar().sum(3);
}
}
編譯:
java -XX+:PrintAssembly -Xcomp -XX:CompileCommand=dontinline, *Bar.sum -XX:CompileCommand=Compileonly, *Bar.sum test.Bar
其中-Xcomp
是讓虛擬機(jī)以編譯模式執(zhí)行代碼颗圣,這樣就不需要執(zhí)行足夠次數(shù)來預(yù)熱就能觸發(fā)JIT
編譯(-Xcomp
在新版本HotSpot
已被移除)。兩個-XX:CompileCommand
是讓編譯器不要內(nèi)聯(lián)sum()
并且只編譯sum()
屁使,-XX+:PrintAssembly
就是輸出反匯編內(nèi)容在岂。如果一切順利會得到如下代碼:
[Disassembling for mach='i386']
[Entry Point]
[Constants]
# {method} 'sum' '(I)I' in 'test/Bar'
# this: ecx = 'test/Bar'
# parm0: edx = int
# [sp+0x20] (sp of caller)
……
0x01cac407: cmp 0x4(%ecx),%eax
0x01cac40a: jne 0x01c6b050 ; {runtime_call}
[Verified Entry Point]
0x01cac410: mov %eax,-0x8000(%esp)
0x01cac417: push %ebp
0x01cac418: sub $0x18,%esp ;*aload_0
; - test.Bar::sum@0 (line 8)
;; block B0 [0, 10]
0x01cac41b: mov 0x8(%ecx),%eax ;*getfield a
; - test.Bar::sum@1 (line 8)
0x01cac41e: mov $0x3d2fad8,%esi ; {oop(a
'java/lang/Class' = 'test/Bar')}
0x01cac423: mov 0x68(%esi),%esi ;*getstatic b
; - test.Bar::sum@4 (line 8)
0x01cac426: add %esi,%eax
0x01cac428: add %edx,%eax
0x01cac42a: add $0x18,%esp
0x01cac42d: pop %ebp
0x01cac42e: test %eax,0x2b0100 ; {poll_return}
0x01cac434: ret
說明:
- 1、
mov %eax,-0x8000(%esp)
:檢查棧溢蛮寂。 - 2蔽午、
push %ebp
:保存上一棧幀基址。 - 3酬蹋、
sub $0x18,%esp
:給新幀分配空間及老。 - 4、
mov 0x8(%ecx),%eax
:取實(shí)例變量a
除嘹,這里0x8(%ecx)
就是ecx+0x8
的意思写半,前面“[Constants]”
節(jié)中提示了“this:ecx = 'test/Bar'”
,即ecx
寄存器中放的就是this
對象的地址尉咕。偏移0x8
是越過this
對象的對象頭,之后就是實(shí)例變量a
的內(nèi)存位置璃岳。這次是訪問“Java堆”
中的數(shù)據(jù)年缎。 - 5悔捶、
mov $0x3d2fad8,%esi
:取test.Bar
在方法區(qū)的指針。 - 6单芜、
mov 0x68(%esi),%esi
:取類變量b
蜕该,這次是訪問“方法區(qū)”中的數(shù)據(jù)。 - 7洲鸠、
add %esi,%eax 堂淡、add %edx,%eax
:做2
次加法,求a+b+c
的值扒腕,前面的代碼把a
放在eax
中绢淀,把b
放在esi
中,而c
在[Constants]
中提示了瘾腰,“parm0:edx = int”
皆的,說明c
在edx
中。 - 8蹋盆、
add $0x18,%esp
:撤銷棧幀费薄。 - 9、
pop %ebp
:恢復(fù)上一棧幀栖雾。 - 10楞抡、
test %eax,0x2b0100
:輪詢方法返回處的SafePoint
- 11、
ret
:方法返回析藕。