jvm優化必知系列——監控工具

這是jvm優化系列第二篇:html

 

經過上一篇的jvm垃圾回收知識,咱們瞭解了jvm對內存分配以及垃圾回收是怎麼來處理的。理論是指導實踐的工具,有了理論指導,定位問題的時候,知識和經驗是關鍵基礎,數據能夠爲咱們提供依據。java

在常見的線上問題時候,咱們多數會遇到如下問題:c++

  • 內存泄露
  • 某個進程忽然cpu飆升
  • 線程死鎖
  • 響應變慢...等等其餘問題。

若是遇到了以上這種問題,在線下能夠有各類本地工具支持查看,但到線上了,就沒有這麼多的本地調試工具支持,咱們該如何基於監控工具來進行定位問題?算法

咱們通常會基於數據收集來定位,而數據的收集離不開監控工具的處理,好比:運行日誌、異常堆棧、GC日誌、線程快照、堆快照等。常用恰當的分析和監控工具能夠加快咱們的分析數據、定位解決問題的速度。如下咱們將會詳細介紹。瀏覽器

 

1、jvm常見監控工具&指令

 

一、 jps:jvm進程情況工具

jps [options] [hostid]

 若是不指定hostid就默認爲當前主機或服務器。 bash

 命令行參數選項說明以下: 服務器

-q 不輸出類名、Jar名和傳入main方法的參數

- l 輸出main類或Jar的全限名

-m 輸出傳入main方法的參數

- v 輸出傳入JVM的參數

例如:網絡

 

二、jstat: jvm統計信息監控工具

jstat  是用於見識虛擬機各類運行狀態信息的命令行工具。它能夠顯示本地或者遠程虛擬機進程中的類裝載、內存、垃圾收集、jit編譯等運行數據,它是線上定位jvm性能的首選工具。oracle

命令格式:框架

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

generalOption - 單個的經常使用的命令行選項,如-help, -options, 或 -version。

outputOptions -一個或多個輸出選項,由單個的statOption選項組成,能夠和-t, -h, and -J等選項配合使用。

參數選項:

Option

Displays

Ex

class

用於查看類加載狀況的統計

jstat -class pid:顯示加載class的數量,及所佔空間等信息。

compiler

查看HotSpot中即時編譯器編譯狀況的統計

 jstat -compiler pid:顯示VM實時編譯的數量等信息。 

gc

查看JVM中堆的垃圾收集狀況的統計

jstat -gc pid:能夠顯示gc的信息,查看gc的次數,及時間。其中最後五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。 

gccapacity

查看新生代、老生代及持久代的存儲容量狀況

 jstat -gccapacity:能夠顯示,VM內存中三代(young,old,perm)對象的使用和佔用大小

gccause

查看垃圾收集的統計狀況(這個和-gcutil選項同樣),若是有發生垃圾收集,它還會顯示最後一次及當前正在發生垃圾收集的緣由。

jstat -gccause:顯示gc緣由

gcnew

查看新生代垃圾收集的狀況

 jstat -gcnew pid:new對象的信息

gcnewcapacity

用於查看新生代的存儲容量狀況

  jstat -gcnewcapacity pid:new對象的信息及其佔用量

gcold

用於查看老生代及持久代發生GC的狀況

jstat -gcold pid:old對象的信息

gcoldcapacity

用於查看老生代的容量

jstat -gcoldcapacity pid:old對象的信息及其佔用量

gcpermcapacity

用於查看持久代的容量

jstat -gcpermcapacity pid: perm對象的信息及其佔用量

gcutil

查看新生代、老生代及持代垃圾收集的狀況

jstat -util pid:統計gc信息統計

printcompilation

HotSpot編譯方法的統計

 jstat -printcompilation pid:當前VM執行的信息

例如:

查看gc 狀況執行:jstat-gcutil 27777

 

三、jinfo: java配置信息

命令格式:

jinfo[option] pid

好比:獲取一些當前進程的jvm運行和啓動信息。

 

四、jmap: java 內存映射工具

jmap命令用於生產堆轉存快照。打印出某個java進程(使用pid)內存內的,全部‘對象’的狀況(如:產生那些對象,及其數量)。

命令格式:

jmap [ option ] pid

jmap [ option ] executable core

jmap [ option ] [server-id@]remote-hostname-or-IP

 

參數選項:

-dump:[live,]format=b,file=<filename> 使用hprof二進制形式,輸出jvm的heap內容到文件=. live子選項是可選的,假如指定live選項,那麼只輸出活的對象到文件. 

-finalizerinfo 打印正等候回收的對象的信息.

-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用狀況.

-histo[:live] 打印每一個class的實例數目,內存佔用,類全名信息. VM的內部類名字開頭會加上前綴」*」. 若是live子參數加上後,只統計活的對象數量. 

-permstat 打印classload和jvm heap長久層的信息. 包含每一個classloader的名字,活潑性,地址,父classloader和加載的class數量. 另外,內部String的數量和佔用內存數也會打印出來. 

-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效. 

-h | -help 打印輔助信息 

-J 傳遞參數給jmap啓動的jvm. 

例如:

使用jmap -heap pid查看進程堆內存使用狀況,包括使用的GC算法、堆配置參數和各代中堆內存使用狀況:

使用jmap -histo[:live] pid查看堆內存中的對象數目、大小統計直方圖。

五、jhat:jvm堆快照分析工具

jhat 命令與jamp搭配使用,用來分析map生產的堆快存儲快照。jhat內置了一個微型http/Html服務器,能夠在瀏覽器找那個查看。不過建議儘可能不用,既然有dumpt文件,能夠從生產環境拉取下來,而後經過本地可視化工具來分析,這樣既減輕了線上服務器壓力,有能夠分析的足夠詳盡(好比 MAT/jprofile/visualVm)等。

六、jstack:java堆棧跟蹤工具

jstack用於生成java虛擬機當前時刻的線程快照。線程快照是當前java虛擬機內每一條線程正在執行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現長時間停頓的緣由,如線程間死鎖、死循環、請求外部資源致使的長時間等待等。

命令格式:

jstack [ option ] pid

jstack [ option ] executable core

jstack [ option ] [server-id@]remote-hostname-or-IP

 

參數:

-F當’jstack [-l] pid’沒有相應的時候強制打印棧信息

-l長列表. 打印關於鎖的附加信息,例如屬於java.util.concurrent的ownable synchronizers列表.

-m打印java和native c/c++框架的全部棧信息.

-h | -help打印幫助信息

pid 須要被打印配置信息的java進程id,能夠用jps查詢.

後續的查找耗費最高cpu例子會用到。

 

2、可視化工具

對jvm監控的常見可視化工具,除了jdk自己提供的Jconsole和visualVm之外,還有第三方提供的jprofilter,perfino,Yourkit,Perf4j,JProbe,MAT等。這些工具都極大的豐富了咱們定位以及優化jvm方式。

這些工具的使用,網上有不少教程提供,這裏就再也不過多介紹了。對於VisualVm來講,比較推薦使用,它除了對jvm的侵入性比較低之外,仍是jdk團隊本身開發的,相信之後功能會更加豐富和完善。jprofilter對於第三方監控工具,提供的功能和可視化最爲完善,目前多數ide都支持其插件,對於上線前的調試以及性能調優能夠配合使用。

另外對於線上dump的heap信息,應該儘可能拉去到線下用於可視化工具來分析,這樣分析更詳細。若是對於一些緊急的問題,必須須要經過線上監控,能夠採用 VisualVm的遠程功能來進行,這須要使用tool.jar下的MAT功能。

 

3、應用

 

一、cpu飆升

在線上有時候某個時刻,可能會出現應用某個時刻忽然cpu飆升的問題。對此咱們應該熟悉一些指令,快速排查對應代碼。

 

1.找到最耗CPU的進程

指令:

top

 

2.找到該進程下最耗費cpu的線程

指令:

top -Hp pid

3.轉換進制

printf 「%x\n」 15332 // 轉換16進制(轉換後爲0x3be4) 

4.過濾指定線程,打印堆棧信息

指令

jstack pid |grep 'threadPid'  -C5 --color 

jstack 13525 |grep '0x3be4'  -C5 --color  //  打印進程堆棧 並經過線程id,過濾獲得線程堆棧信息。

能夠看到是一個上報程序,佔用過多cpu了(以上例子只爲示例,自己耗費cpu並不高)

 

二、線程死鎖 

有時候部署場景會有線程死鎖的問題發生,但又不常見。此時咱們採用jstack查看下一下。好比說咱們如今已經有一個線程死鎖的程序,致使某些操做waiting中。

 

1.查找java進程id

指令:

top 或者 jps 

 

2.查看java進程的線程快照信息

指令:

jstack -l pid

從輸出信息能夠看到,有一個線程死鎖發生,而且指出了那行代碼出現的。如此能夠快速排查問題。

 

三、OOM內存泄露

java堆內的OOM異常是實際應用中常見的內存溢出異常。通常咱們都是先經過內存映射分析工具(好比MAT)對dump出來的堆轉存快照進行分析,確認內存中對象是否出現問題。

固然了出現OOM的緣由有不少,並不是是堆中申請資源不足一種狀況。還有多是申請太多資源沒有釋放,或者是頻繁頻繁申請,系統資源耗盡。針對這三種狀況我須要一一排查。

 

OOM的三種狀況:

1.申請資源(內存)太小,不夠用。

2.申請資源太多,沒有釋放。

3.申請資源過多,資源耗盡。好比:線程過多,線程內存過大等。

 

1.排查申請申請資源問題。

指令:jmap -heap 11869

 查看新生代,老生代堆內存的分配大小以及使用狀況,看是否自己分配太小。

從上述排查,發現程序申請的內存沒有問題。

2.排查gc

特別是fgc狀況下,各個分代內存狀況。

指令:jstat -gcutil 11938 1000 每秒輸出一次gc的分代內存分配狀況,以及gc時間

3.查找最費內存的對象

指令: jmap -histo:live 11869 | more

上述輸出信息中,最大內存對象才161kb,屬於正常範圍。若是某個對象佔用空間很大,好比超過了100Mb,應該着重分析,爲什麼沒有釋放。

 

注意,上述指令:

jmap -histo:live 11869 | more

執行以後,會形成jvm強制執行一次fgc,在線上不推薦使用,能夠採起dump內存快照,線下采用可視化工具進行分析,更加詳盡。

jmap -dump:format=b,file=/tmp/dump.dat 11869 

或者採用線上運維工具,自動化處理,方便快速定位,遺失出錯時間。

 

4.確認資源是否耗盡

  • pstree 查看進程線程數量
  • netstat 查看網絡鏈接數量

或者採用:

  • ll /proc/${PID}/fd | wc -l  // 打開的句柄數
  • ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l) //打開的線程數

 

以上就是一些常見的jvm命令應用。

一種工具的應用並不是是萬能鑰匙,包治百病,問題的解決每每是須要多種工具的結合才能更好的定位問題,不管使用何種分析工具,最重要的是熟悉每種工具的優點和劣勢。這樣才能取長補短,配合使用。

 

 

-----------------------------------------------------------------------------

想看更多有趣原創的技術文章,掃描關注公衆號。

關注我的成長和遊戲研發,推進國內遊戲社區的成長與進步。

相關文章
相關標籤/搜索