6、虛擬機(jī)性能監(jiān)控與故障處理工具(1)(JVM筆記)

一设褐、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ù)管理器或UNIXps命令也可以查詢到虛擬機(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)程,VMIDLVMID是一致的笛厦,如果是遠(yuǎn)程虛擬機(jī)進(jìn)程纳鼎,那VMID的格式應(yīng)當(dāng)是:

[ protocol: ][ // ] lvmid [ @hostname [ :port ] / servername ]

其中intervalcount代表查詢間隔和次數(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編譯的方法

下面通過一個例子簡單了解一下:

1

說明:這臺服務(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 GCYGC送矩,表示Young GC16次,總耗時0.105s哪替,發(fā)生Full GCFGC栋荸,表示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)儲快照(一般稱為headdumpdump文件)仁卷。如果不實(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平臺有效

例如:(3500LVMID

2

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)用此方法做個管理員頁面辐宾,隨時查看線程堆棧狱从。


3

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)生成的本地代碼還原為匯編輸出,同時還生成大量非常有價值的注釋檩奠,這樣我們就可以通過輸出的代碼來分析問題桩了。注意,如果使用的DebugFastDebug版的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”皆的,說明cedx中。
  • 8蹋盆、add $0x18,%esp:撤銷棧幀费薄。
  • 9、pop %ebp:恢復(fù)上一棧幀栖雾。
  • 10楞抡、test %eax,0x2b0100:輪詢方法返回處的SafePoint
  • 11、ret:方法返回析藕。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末召廷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子噪径,更是在濱河造成了極大的恐慌柱恤,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件找爱,死亡現(xiàn)場離奇詭異梗顺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)车摄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門寺谤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吮播,你說我怎么就攤上這事变屁。” “怎么了意狠?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵粟关,是天一觀的道長。 經(jīng)常有香客問我环戈,道長闷板,這世上最難降的妖魔是什么澎灸? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮遮晚,結(jié)果婚禮上性昭,老公的妹妹穿的比我還像新娘。我一直安慰自己县遣,他們只是感情好糜颠,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萧求,像睡著了一般其兴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饭聚,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天忌警,我揣著相機(jī)與錄音,去河邊找鬼秒梳。 笑死法绵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酪碘。 我是一名探鬼主播朋譬,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼兴垦!你這毒婦竟也來了徙赢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤探越,失蹤者是張志新(化名)和其女友劉穎狡赐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钦幔,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枕屉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鲤氢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搀擂。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卷玉,靈堂內(nèi)的尸體忽然破棺而出哨颂,到底是詐尸還是另有隱情,我是刑警寧澤相种,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布威恼,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沃测。R本人自食惡果不足惜缭黔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一食茎、第九天 我趴在偏房一處隱蔽的房頂上張望蒂破。 院中可真熱鬧,春花似錦别渔、人聲如沸附迷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喇伯。三九已至,卻和暖如春拨与,著一層夾襖步出監(jiān)牢的瞬間稻据,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工买喧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捻悯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓淤毛,卻偏偏與公主長得像今缚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子低淡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容