JVM性能分析&故障排查

1、Jps查看進程

  1. 首先查看jps都用哪些命令,使用jps -help幫助查看命令,這樣就不用死記硬背了,如下所示:
  2. image.png
  3. 首先用jps命令查看正在運行中的進程的pid等。
    • jps -l    輸出主類的全名,如果進程執行的是 Jar 包,輸出 Jar 路徑。
    • jps -v:輸出虛擬機進程啓動時 JVM 參數。(經常使用,類似ps - ef |grep java 但比這個顯示更清晰)
    • jps -m:輸出傳遞給 Java 進程 main() 函數的參數。

 

2、jstat性能分析(調優使用)

  1. jstat 命令它可以顯示出虛擬機進程中的類裝載、內存、垃圾收集、JIT編譯等運行數據
  • 首先可以自己在Liunx上用jstat -help查看一下有哪些命令可以使用,這個很好用的,不用讓我們死記硬背大量的命令了,用法如下:
  1. 查看jvm內存,以及使用情況(常用)
    • jstat -gc pid  (jps查看進程id)
    • 運行這個命令之後大家會看到如下所示:
    • image.png
    • 參數解釋如下:
    • image.png
  1. 除了上面jstat -gc是最常用的命令之外,還有一些其他命令,如下所示:
    • jstat -gccapacity pid:堆內存分析、顯示各個代的容量及使用情況;
    • jstat -gcnew pid:年輕代GC分析,這個的TT和MTT可以看到對象在年輕代存活的年齡和存活的最大年齡
    • image.png
    • stat -class pid:顯示 ClassLoader 的相關信息;
    • jstat -compiler pid:顯示 JIT 編譯的相關信息;
    • jstat -gcnewcapcacity pid:顯示新生代大小與使用情況;
    • jstat -gcold pid:顯示老年代和永久代的信息;
    • jstat -gcoldcapacity pid:顯示老年代的大小;
    • jstat -gcpermcapacity pid:顯示永久代大小;
    • jstat -gcutil pid:顯示垃圾收集信息;
    • 另外,加上 -t參數可以在輸出信息上加一個 Timestamp 列,顯示程序的運行時間。
    • 比如 jstat -gc -h3 31736 1000 10表示分析進程 id 爲 31736 的 gc 情況,每隔 1000ms 打印一次記錄,打印 10 次停止,每 3 行後打印指標頭部。
  1. jstat使用分析
    • 首先我們分析線上jvm進程,最想知道哪些信息呢?
    • 至少得包括如下,新生代:
      • 新生代對象增長速率
      • Young GC的觸發頻率
      • Young GC的耗時
      • 每次Yong GC後有多少對象是存活下來的
      • 每次Yong GC之後有多少對象進入了老年代
    • 老年代:
      • 老年代對象增長速率
      • Full GC 的觸發頻率
      • Full GC的耗時
    • 使用jstat知道了上面的信息,我們就可以合理的分配內存空間,儘可能的讓對象留在年輕代被回收,而不是進入老年代,避免頻繁的發生Full GC,這就是對JVM最好的性能優化了!
  1. 計算新生代對象增長速率
    1. 隨着系統運行,每秒鐘會在年輕代Eden區分配多少對象呢?
    2. 要分析這個,只需要在Liunx上運行命令: jstat -gc pid  1000  10
    3. 每隔1000ms(也可幾分鐘打印一次)也就是1s中打印一行jstat統計信息,一共執行10次停止
    4. 通過這個命令打印的日誌信息,你可以對線上的機器通過固定頻率輸出的統計信息,觀察jvm中Eden中的使用變化
      • 舉例:第一秒Eden使用了200M,第二面打印信息使用了204.6M,第三秒打印信息使用了211.2M等,那麼就可以推斷系統每秒大概新增5M對象
  1. 計算Yong GC觸發頻率和每次耗時
    1. 通過查看jvm新生代內存的分配大小除以上面觀察新生代每秒新增的對象大小,就可以大致分析出來每個多長時間會發生一次Yong GC了
    2. 那麼每次Yong GC的平均耗時呢?
    3. jstat會告訴你到現在系統已經發生了多少次Yong GC以及這些GC的總耗時,那麼就可以計算出GC時會導致系統STW多少時間
  1. 每次Yong GC之後有多少對象是存活的和進入老年代的
    1. 分析方法也是如上述差不多,可以使用jstat -gc pid  3分鐘 10
    2. 比如3分鐘是上面分析出來的Yong GC的頻率,那麼就可以看下每次Yong GC之後,老年代內存使用率會增加多少
  1. Full GC觸發時機和耗時
    • 只要知道了老年代對象增長速率,那麼FullGc的觸發時機就很好算了,用老年代分配的內存除以老年代對象的增長大小就可以算出大概多久老年代會滿,會執行一次Full GC

 

3、Jmap查看內存

  1. 首先使用jmap -help查看有哪些命令可以使用
    • image.png    

3.1、Jmap和Jhat兩個最常用的命令

  1. jmap -histo pid
    • 這個命令會按照各種對象佔用的內存空間大小降序排列,把佔用內存最多的隊形放在最上面
    • 這樣就可以看到到底是哪個對象佔用了大量的內存空間了
    • image.png
  1. 使用jmap生成堆內存快照
    • 上面的方式只能看一個大概,如果想要更詳細的看,則用生成堆內存快照的方式
    • jmap -dump:live,format=b,file=dump.hprof pid
    • 當然file=也可以指定快照生成文件夾,並且生成的文件後綴也可以是.log .bin等之類的,例如我這邊測試的如下兩種方式:
    • image.pngimage.png
    • image.pngimage.png
  1. 使用jhat分析jvm內存快照
    • 上面是dump下當前的內存快照,但是他是二進制的我們不方便查看,所以這裏可以使用jdk自帶的jhat在瀏覽器上分析
    • 使用命令jhat  /usr/local/heap.bin  默認端口爲7000 (-port 7001  可以指定端口)
    • 瀏覽器訪問http://ip:7000,可以詳細查看,示例如下:
    • image.png
    • 對於jhat啓動後顯示的html頁面中功能:顯示出堆中所包含的所有的類
    • 詳情參考:https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html

3.2、Jmap其他命令

  • jmap -histo:live pid
    • 描述:顯示堆中對象的統計信息,其中包括每個Java類、對象數量、內存大小(單位:字節)、完全限定的類名。打印的虛擬機內部的類名稱將會帶有一個’*’前綴。如果指定了live子選項,則只計算活動的對象。
  • 命令:jmap -clstats pid
    • 描述:打印類加載器信息 ,-clstats是-permstat的替代方案,在JDK8之前,-permstat用來打印類加載器的數據

打印Java堆內存的永久保存區域的類加載器的智能統計信息。對於每個類加載器而言,它的名稱、活躍度、地址、父類加載器、            它 所加載的類的數量和大小都會被打印。此外,包含的字符串數量和大小也會被打印。

4、Jstack查看線程

  • 首先查看幫助jstack -help
  • image.png

4.1、cpu使用率過高

  1. 可以通過jstack來分析
  2. 首先使用jps找到需要查看的進程pid
  3. 接着找出該進程最消耗CPU的線程,可以使用top -Hp 26048或者ps -Lfp 26048來查看該進程中線程的cpu消耗情況
  4. 查看到線程26094的消耗CPU時間是最長的,用命令查看該線程的十六進制值
[root@dzt-test-5-52 promotion-core]#  printf "%x\n" 26094
65ee

查詢到的值65ee用於下面jstack 定位信息(jstack 進程號|grep 65ee)

[root@dzt-test-5-52 promotion-core]# jstack 26048|grep 65ee
"redisson-netty-4-5" #34 prio=5 os_prio=0 tid=0x00007fa3462cd000 nid=0x65ee runnable [0x00007fa2e4bd7000]


這樣就可以看到redisson-netty-4-5是最耗時的類,然後就可以去代碼審查代碼了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章