JVM問題排查小工具

注:最近一直想出一篇介紹JVM底層函數(shù)調(diào)用的博客,奈何越寫越多,現(xiàn)在還沒寫完穿剖,先來個簡單的安慰下我受傷的心靈

滴滴...報警短信又來了~~~打開一看冬竟,xxx系統(tǒng)內(nèi)存使用率達(dá)90%欧穴,請盡快處理。一臉懵逼泵殴,昨天還60%涮帘,今天怎么就90%了,內(nèi)存泄漏了么笑诅?

相信這個場景絕大多數(shù)猿都不陌生调缨,出現(xiàn)這個問題了我們該怎么辦呢?Java的內(nèi)存分配和垃圾收集都對開發(fā)者不透明吆你,我們要怎么排查這類型的問題呢弦叶?接下來,就讓我早处,來給你們介紹幾款排查JVM問題的小工具湾蔓。

JDK提供的命令工具

作為一個Java程序猿,大家肯定都知道jdk的bin目錄下有java砌梆,javac這倆命令默责,但是bin下其實還有好多其他的命令贬循,我相信并不是所有的程序猿都非常了解這些命令。這次我要介紹排查JVM問題的小工具呢也就在bin目錄下桃序。先來看下bin目錄下的命令集們:

bin目錄下命令集

這些可愛的命令集們是java開發(fā)者們送給JDK使用者們的小禮物杖虾,它們可以幫助我們快速在遇到JVM問題可以快速排查并定位bug。

注:bin目錄下的命令集們體積都很小媒熊,體積小并不是java開發(fā)者們在炫耀技術(shù)奇适,而是這些命令其實大多都是包裝jdk/lib/tools.jar,至于為什么選擇用java來實現(xiàn)這些命令也是為了便于在應(yīng)用程序中直接實現(xiàn)JVM的監(jiān)控和分析芦鳍。

排查JVM問題命令工具

JDK提供以下命令排查JVM問題:

  • jps:JVM Process Status Tool嚷往,顯示系統(tǒng)內(nèi)所有的JVM進(jìn)程;

  • jstat:JVM Statistics Monitoring Tool柠衅,可以收集JVM相關(guān)的運行數(shù)據(jù)皮仁;

  • jinfo:Configuration Info for Java,顯示JVM配置信息菲宴;

  • jmap:Memory Map for Java贷祈,用于生成JVM的內(nèi)存快照;

  • jhat:JVM Heap Dump Browser喝峦,用于分析heapdump文件势誊,它可以建立一個http/html服務(wù),使用者可以在瀏覽器上查看分析結(jié)果谣蠢;

  • jstack:Stack Trace for Java粟耻,顯示JVM的線程快照。

接下來就針對這幾個命令的使用做相關(guān)分析漩怎。

jps

列出正在運行的虛擬機進(jìn)程勋颖,并顯示虛擬機執(zhí)行主類名稱以及這些進(jìn)程的本地虛擬機唯一id(Local Virtual Machine Identifier,簡稱LVMID)勋锤。相比其他命令來說饭玲,它的功能其實比較單一,但是它的使用頻率確實非常高的叁执,因為其他的JDK命令大多都需要輸入虛擬機進(jìn)程id茄厘。

注:看到這里小伙伴們可能就會比較困惑了,因為在大多數(shù)使用JDK命令時谈宛,我們都用的是pid(操作系統(tǒng)進(jìn)程id)啊次哈,那pid和LVMID到底有什么區(qū)別呢?其實吆录,很負(fù)責(zé)任的告訴你窑滞,對于本地虛擬機進(jìn)程來說,它倆無差別,用ps命令也可以查詢到哀卫,但是如果同時啟動多個虛擬機進(jìn)程無法根據(jù)進(jìn)程名稱定位時巨坊,jps命令就派上用場了,可以輸出主類名稱此改,通過主類名稱來區(qū)分趾撵。

jps命令格式:

jps命令格式

jps主要提供以下選項:

  • -q
    只輸出LVMID,省略主類名稱共啃;

  • -m
    輸出虛擬機進(jìn)程啟動時傳給主類函數(shù)的參數(shù)占调;

  • -l
    輸出主類的完成package名稱或者jar包完整路徑名;

  • -v
    輸出虛擬機啟動時的JVM參數(shù)

接下來我們來看看它的實際使用:

  • 測試代碼:
    測試代碼
  • 使用結(jié)果:
    jps使用結(jié)果
jstat

用于監(jiān)控虛擬機運行狀態(tài)信息移剪。它可以顯示本地或者遠(yuǎn)程虛擬機進(jìn)程的內(nèi)存究珊、垃圾收集、JIT編譯等運行數(shù)據(jù)挂滓。

jstat命令格式:

jstat命令格式

jstat命令稍許有些復(fù)雜苦银,它主要有以下參數(shù):

  1. option:選項,jstat主要提供以下選項:

    • -class
      監(jiān)視類的裝載/卸載數(shù)量赶站、總空間以及類裝載所耗時間;

    • -gc
      監(jiān)視java heap情況纺念,包括eden區(qū)和兩個survivor區(qū)贝椿、old區(qū)、永久區(qū)等的容量陷谱,已用空間和GC時間等信息烙博;

    • -gccapacity
      監(jiān)視內(nèi)容與-gc基本是一致的,-gccapacity的輸出包括heap各個區(qū)域使用到的最大最小空間烟逊;

    • gcutil
      監(jiān)視內(nèi)容同樣與-gc基本一致渣窜,-gcutil的輸出主要是heap各個區(qū)域使用空間占總空間百分比;

    • gccause
      -gcutil功能一致宪躯,但是會額外輸出導(dǎo)致上一次gc的原因乔宿;

    • gcnew
      監(jiān)視young區(qū)gc情況;

    • gcnewcapacity
      監(jiān)視內(nèi)容與-gcnew基本相同访雪,-gcnewcapacity的輸出包括使用到的最大最小空間详瑞;

    • -gcold
      監(jiān)視old區(qū)gc情況;

    • -gcoldcapacity
      監(jiān)視內(nèi)容與-gcold基本相同臣缀,-gcoldcapacity的輸出包括使用到的最大最小空間坝橡;

    • -gcpermcapacity
      輸出永久代使用到的最大最小空間;

    注:JDK 8廢除了永久代精置,引入了Metaspace计寇,這個命令在JDK 8的環(huán)境下就不能使用了,那要看元數(shù)據(jù)空間相關(guān)情況,使用-gcmetacapacity即可

    • -compiler
      輸出JIT編譯器編譯過的方法以及耗時等信息番宁;
    • -printcompilation
      輸出以及被JIT編譯的方法
  2. vmid:虛擬機進(jìn)程id元莫,這時候小伙伴們肯定又要開始疑惑了,這個vmid與lvmid又有什么區(qū)別贝淤?其實對于本地虛擬機進(jìn)程柒竞,它倆沒任何區(qū)別,但是如果是遠(yuǎn)程虛擬機進(jìn)程播聪,它倆就有區(qū)別了朽基,遠(yuǎn)程虛擬機進(jìn)程vmid格式應(yīng)該是這樣:
    [protocol:][//] lvmid [@hostname[:port]/servername]

  3. interval:查詢時間間隔离陶;

  4. count:查詢次數(shù)稼虎。

注:如果參數(shù)interval和count省略則代表只查詢一次;如果count省略的話招刨,就會一直查詢霎俩。來個簡單的例子:jstat -gcnewcapacity 41503 1000,表示輸出進(jìn)程41503的young區(qū)使用及gc情況沉眶,每1000ms輸出一次打却。

接下來就部分option給出實例,同時分析下輸出谎倔。

jstat使用

  1. jstat -class <vmid>


    jstat -class輸出
    • Loaded:裝載的類的數(shù)量柳击;

    • Bytes:裝載類所占用的字節(jié)數(shù);

    • Unloaded:卸載類數(shù)量片习;

    • Bytes:卸載類所占用的字節(jié)數(shù)捌肴;

    • Time:裝載和卸載類所花時間。

  2. jstat -compiler <vmid>


    jstat -compiler輸出
    • Compiled:編譯任務(wù)執(zhí)行數(shù)量藕咏;

    • Failed:編譯任務(wù)執(zhí)行失敗數(shù)量状知;

    • Invalid:編譯任務(wù)執(zhí)行失效數(shù)量;

    • Time:編譯任務(wù)消耗時間孽查;

    • FailedType:最后一個編譯失敗任務(wù)的類型饥悴;

    • FailedMethod:最后一個編譯失敗任務(wù)所在的類及方法。

  3. jstat -gc <vmid>


    jstat -gc輸出
    • S0C:young區(qū)中的第一個survivor區(qū)的大胸阅搿铺坞;

    • S1C:young區(qū)中的第二個survivor區(qū)的大小洲胖;

    • S0U:young區(qū)中的第一個survivor區(qū)目前已使用空間济榨;

    • S1U:young區(qū)中的第二個survivor區(qū)目前已使用空間;

    • EC:young區(qū)中的eden區(qū)的大新逃场擒滑;

    • EU:young區(qū)中的eden區(qū)目前已使用空間腐晾;

    • OC:old區(qū)的大小丐一;

    • OU:old區(qū)目前已使用空間藻糖;

    • MC:元數(shù)據(jù)區(qū)大小库车;

    • MU:元數(shù)據(jù)區(qū)使用大芯奁狻;

    • CCSC:壓縮類空間大心堋洋满;

    • CCSU:壓縮類空間使用大小珍坊;

    • YGC:young gc次數(shù)牺勾;

    • YGCT:young gc消耗時間;

    • FGC:full gc次數(shù)阵漏;

    • FGCT:full gc消耗時間驻民;

    • GCT:gc消耗時間。

  4. jstat -gcutil <vmid>


    jstat -gcutil輸出
    • S0:young區(qū)中的第一個survivor區(qū)的使用比例履怯;

    • S1:young區(qū)中的第二個survivor區(qū)的使用比例回还;

    • E:young區(qū)中的eden區(qū)的使用比例;

    • O:old區(qū)使用比例叹洲;

    • M:元數(shù)據(jù)區(qū)使用比例懦趋;

    • CCS:壓縮類空間使用比例;

    • YGC:young gc次數(shù)疹味;

    • YGCT:young gc消耗時間;

    • FGC:full gc次數(shù)帜篇;

    • FGCT:full gc消耗時間糙捺;

    • GCT:gc消耗時間。

  5. jstat -gccapacity <vmid>


    jstat -gccapacity輸出
    • NGCMN:young區(qū)最小容量笙隙;

    • NGCMX:young區(qū)最大容量洪灯;

    • NGC:當(dāng)前young區(qū)容量;

    • S0C:young區(qū)中的第一個survivor區(qū)的大芯固怠签钩;

    • S1C:young區(qū)中的第二個survivor區(qū)的大小坏快;

    • EC:young區(qū)中的eden區(qū)的大星﹂荨;

    • OGCMN:old區(qū)最小容量莽鸿;

    • OGCMX:old區(qū)最大容量昧旨;

    • OGC:當(dāng)前old區(qū)大惺案;

    • OC:當(dāng)前old區(qū)的大型梦帧蒋得;

    • MCMN:元數(shù)據(jù)區(qū)最小容量;

    • MCMX:元數(shù)據(jù)區(qū)最大容量乒疏;

    • MC:當(dāng)前元數(shù)據(jù)區(qū)大卸钛谩;

    • CCSMN:壓縮類空間最小容量怕吴;

    • CCSMX:壓縮類空間最大容量窍侧;

    • CCSC:當(dāng)前壓縮類空間大小械哟;

    • YGC:young gc次數(shù)疏之;

    • FGC:old gc次數(shù)。

  6. jstat -gcnew <vmid>


    jstat -gcnew輸出
    • S0C:young區(qū)中的第一個survivor區(qū)的大邢九亍锋爪;

    • S1C:young區(qū)中的第二個survivor區(qū)的大小爸业;

    • S0U:young區(qū)中的第一個survivor區(qū)目前已使用空間其骄;

    • S1U:young區(qū)中的第二個survivor區(qū)目前已使用空間;

    • TT:對象在young區(qū)存活的次數(shù)扯旷;

    • MTT:對象在young區(qū)存活的最大次數(shù)拯爽;

    • DSS:期望survivor區(qū)大小钧忽;

    • EC:young區(qū)中的eden區(qū)的大刑号凇;

    • EU:young區(qū)中的eden區(qū)目前已使用空間耸黑;

    • YGC:young gc次數(shù)桃煎;

    • YGCT:young gc消耗時間。

  7. jstat -gcold <vmid>


    jstat -gcold輸出
    • MC:元數(shù)據(jù)空間大写罂为迈;

    • MU:元數(shù)據(jù)空間使用大小缺菌;

    • CCSC:壓縮類空間大泻;

    • CCSU:壓縮類空間使用大邪橛簟耿战;

    • OC:old區(qū)大小蛾绎;

    • OU:old區(qū)使用大欣セ鸦列;

    • YGC:young gc次數(shù);

    • FGC:full gc次數(shù)鹏倘;

    • FGCT:full gc消耗時間薯嗤;

    • GCT:gc消耗時間。

  8. jstat -gcmetacapacity <vmid>


    jstat -gcmetacapacity輸出
    • MCMN:元數(shù)據(jù)區(qū)最小容量纤泵;

    • MCMX:元數(shù)據(jù)區(qū)最大容量骆姐;

    • MC:元數(shù)據(jù)區(qū)大小捏题;

    • CCSMN:壓縮類空間最小容量玻褪;

    • CCSMX:壓縮類空間最大容量;

    • CCSC:壓縮類空間大泄带射;

    • YGC:young gc次數(shù);

    • FGC:full gc次數(shù)循狰;

    • FGCT:full gc消耗時間窟社;

    • GCT:gc消耗時間。

  1. jstat -printcompilation <vmid>


    jstat -printcompilation輸出
    • Compiled:編譯方法數(shù)量绪钥;

    • Size:編譯方法的字節(jié)碼數(shù)量灿里;

    • Type:編譯方法的編譯類型;

    • Method:方法名稱程腹。

針對young區(qū)和old區(qū)相關(guān)capacity命令在這里就不做詳細(xì)分析了匣吊,有興趣的小伙伴自行敲一敲命令運行下,至于輸出的表格列含義在前幾個命令詳細(xì)介紹中基本上都包括在內(nèi)了寸潦。

注:在使用jstat命令輸出的容量的單位是字節(jié)色鸳。

jinfo

用于實時查看和調(diào)整虛擬機參數(shù)。

jinfo命令格式

jinfo命令格式

jinfo命令主要有以下參數(shù):

  1. option:選項见转,jinfo主要提供以下選項:

    • -flag <name>
      輸出指定JVM參數(shù)值缕碎;

    • -flag [+|-]<name>
      啟用或禁用指定JVM參數(shù);

    • -flag <name>=<value>
      設(shè)置指定JVM參數(shù)值池户;

    • -flags
      輸出所有JVM參數(shù)

    • -sysprops
      輸出Java系統(tǒng)屬性;

    • <no option>
      不指定選項則輸出所有的虛擬機參數(shù)和Java系統(tǒng)屬性

  2. pid:需要查看或者調(diào)整虛擬機參數(shù)的進(jìn)程id

接下來我們來看看它的實際使用:


jinfo使用結(jié)果
jmap

用于生成堆內(nèi)存快照(heapdump或者dump文件)凡怎。當(dāng)然校焦,如果不想使用jmap命令,也可以使用JVM參數(shù)來生成:

  • -XX:+HeapDumpOnOutOfMemoryError统倒,如果虛擬機在出現(xiàn)OutOfMemory異常后生成dump文件寨典;

  • -XX:+HeapDumpOnCtrlBreak,使用ctrl + break鍵讓虛擬機生成dump文件房匆。

當(dāng)然耸成,還有一種更暴力的方式就是在linux系統(tǒng)下报亩,kill -3也可以讓虛擬機生成dump文件。

jmap命令格式

jmap命令格式

相比jstat命令井氢,jmap命令明顯就簡單的多了弦追,就兩個參數(shù):

  1. option:選項,jmap主要提供以下選項:

    • -dump
      生成Java堆內(nèi)存快照花竞,使用格式為:-dump:[live, ]format=b,file=<filename>劲件,使用hprof二進(jìn)制形式,輸出jvm的heap內(nèi)容到文件<filename>约急,live子參數(shù)是可選的零远,如果指定live選項,就只dump出存活的對象厌蔽;

    • finalizerinfo
      顯示在F-Queue中等待Finalizer線程執(zhí)行finalize方法的對象牵辣;

    • -heap
      顯示heap詳細(xì)信息,比如使用哪種回收器奴饮、參數(shù)配置纬向、分代狀態(tài)等;

    • histo
      顯示每個class的實例數(shù)目拐云,內(nèi)存占用罢猪,類全名信息。VM的內(nèi)部類名字開頭會加上前綴“*”.叉瘩,如果帶上live子參數(shù)膳帕,則只統(tǒng)計活的對象數(shù)量;

    • -permstat
      以ClassLoader為統(tǒng)計口徑顯示永久代內(nèi)存狀態(tài)薇缅,需要注意的是危彩,JDK 8將該option替換成了-clstats

    • -F
      強制生成dump文件泳桦,當(dāng)虛擬機進(jìn)程對-dump選項沒有響應(yīng)時可以使用汤徽。

  2. pid:需要生成dump文件的進(jìn)程id

dump文件在這里我就不做演示了,給一個簡單的使用吧:


jmap -histo輸出

從輸出的結(jié)果可以清晰的看出每一個class的實例數(shù)目以及內(nèi)存占用情況灸撰。

jstack

用戶生成虛擬機當(dāng)前時刻的線程快照(threaddump/javacore文件)谒府。線程快照就是當(dāng)前虛擬機內(nèi)每一條線程正在執(zhí)行的方法堆棧集合,生成線程快照的目的也就是為了定位線程出現(xiàn)長時間卡頓的原因浮毯。

jstack命令格式

jstack命令格式

跟jmap命令一樣完疫,jstack命令也只有兩個參數(shù):

  1. option:選項,jstack主要提供以下選項:

    • -F
      當(dāng)線程出現(xiàn)長時間卡頓的時候债蓝,強制輸出線程堆棧壳鹤;

    • -l
      除堆棧外,顯示關(guān)于鎖的附加信息饰迹;

    • -m
      如果調(diào)用JNI方法芳誓,可以顯示C/C++的堆棧余舶。

  2. pid:需要生成threaddump的進(jìn)程id。

簡單給一個使用吧還是:


jstack -l輸出

從輸出結(jié)果可以清晰的看到線程堆棧以及鎖相關(guān)信息锹淌。具體的怎么根據(jù)threaddump分析定位問題最近暫時沒有遇到匿值,等遇到了再出文詳細(xì)介紹啦~

jhat

與jmap命令搭配使用,分析jmap生成的dump文件葛圃。jhat內(nèi)置一個微型的HTTP/HTML服務(wù)器千扔,生成dump文件的分析結(jié)果后,可以在瀏覽器中進(jìn)行查看库正。其實這個命令在實際生產(chǎn)中使用比較少曲楚,為什么不用的原因我總結(jié)下來大概有兩點:第一呢,線上生產(chǎn)環(huán)境怎么可能允許你在線上機器直接分析dump文件啊~~~第二就是jhat的分析功能相比其他工具簡直是太簡陋了褥符。

它的使用也很簡單啊龙誊,jhat <dump文件名稱>,等分析完就打開瀏覽器訪問相應(yīng)的地址+端口就可以愉快的開始分析dump文件了喷楣。我在這里就不再做詳細(xì)使用實例分析啦趟大,有興趣的小伙伴們請自行嘗試~

寫在最后面

本文只是粗糙的介紹了怎么使用命令排查JVM問題,但是小伙伴們一定不要以為會命令就會排查了铣焊,一定要親自擼起袖子查幾輪問題才能熟練理解掌握逊朽,當(dāng)然我也會在后續(xù)出一些我排查線上問題的小文章啦~歡迎大家持續(xù)關(guān)注呀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末曲伊,一起剝皮案震驚了整個濱河市叽讳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坟募,老刑警劉巖岛蚤,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異懈糯,居然都是意外死亡涤妒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門赚哗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來她紫,“玉大人,你說我怎么就攤上這事屿储±缢眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵扩所,是天一觀的道長。 經(jīng)常有香客問我朴乖,道長祖屏,這世上最難降的妖魔是什么助赞? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮袁勺,結(jié)果婚禮上雹食,老公的妹妹穿的比我還像新娘。我一直安慰自己期丰,他們只是感情好群叶,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钝荡,像睡著了一般街立。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埠通,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天赎离,我揣著相機與錄音,去河邊找鬼端辱。 笑死梁剔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舞蔽。 我是一名探鬼主播荣病,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渗柿!你這毒婦竟也來了个盆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤做祝,失蹤者是張志新(化名)和其女友劉穎砾省,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體混槐,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡编兄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了声登。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狠鸳。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖悯嗓,靈堂內(nèi)的尸體忽然破棺而出件舵,到底是詐尸還是另有隱情,我是刑警寧澤脯厨,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布铅祸,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏临梗。R本人自食惡果不足惜涡扼,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盟庞。 院中可真熱鬧吃沪,春花似錦、人聲如沸什猖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽不狮。三九已至降铸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荤傲,已是汗流浹背垮耳。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留遂黍,地道東北人终佛。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像雾家,于是被迫代替她去往敵國和親铃彰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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