一、Dump文件是什麼
你們確定知道咱們java應用的對象的建立是由咱們管,可是回收大多數是由jvm經過必定的算法來自動實現的,如:最少使用、不可達、新生代的複製清除等,也就是jvm會按照你現有對象佔用的新生代或老年代的內存比例決定是否進行垃圾回收,每次垃圾回收都是須要STW的,可是當對象非正常產生的時候,jvm是回收不過來的,會形成不應有的對象直接將內存佔滿甚至超過jvm設置大小,形成系統運行緩慢或者OOM。java
當出現運行緩慢或者OOM的時候,咱們就須要掌握jvm的內存狀態來查找咱們系統變慢或者卡頓的緣由。Java官方提供了生成jvm內存快照文件(dump文件)的工具jmap ,使用jmap便可生成。web
同時,咱們還能夠經過dump文件分析系統運行時的狀況。針對特定卡慢的方法進行優化。算法
一、Dump文件的生成
2.1、Linux生成dump文件
2.1.1、Linux上使用命令生成內存dump文件
一、執行 ps -ef | grep [應用名稱] --獲取 [pid]
2、執行 jmap -dump:format=b,file=filename [pid] 生成內存的dump文件,生成時間可能較久數據庫
2.1.2、Linux上使用命令生成線程dump文件
Jstack [pid] filename 就能夠生成線程dump文件。jvm
2.1.3、內存dump文件和線程dump的區別
內存dump文件着重當前應用的jvm的內存被哪些對象佔用,線程dump文件着重顯示當前應用的各線程的運行狀況,容易定位死鎖等問題。如圖。線程dump:工具
觀測線程dump文件的時候要特別注意:java.lang.Thread.State:Blocked,這種狀態可能出現了線程死鎖,而後形成系統卡頓。測試
所謂的線程死鎖:線程T1正在佔用R1資源,須要獲取R2資源才能執行完成,而後釋放R1資源的鎖。線程T2正在佔用R2資源,須要獲取R1資源才能執行完成,而後釋放R2資源的鎖。這就形成兩個線程相互等待對方釋放鎖資源,線程沒法向前執行。解決方式:加1、鎖順序(線程按照必定的順序加鎖)
2、加鎖時限(線程嘗試獲取鎖的時候加上必定的時限,超過期限則放棄對該鎖的請求,並釋放本身佔有的鎖)
3、死鎖檢測優化
內存dumpspa
稍後,咱們對內存dump文件進項詳細介紹。線程
2.2、在出現OOM時自動保存dump文件
二、經過jvm參數--XX:+HeapDumpOnOutOfMemoryError可讓JVM在出現內存溢出時候自動Dump出當前的內存轉儲快照。
3、Dump使用場景及問題分析思路
上線過程當中可能會遇到各類各樣的問題,大多數的問題咱們經過分析日誌就能夠得出結論,找到緣由。
可是會出現一種問題咱們很難經過日誌找到緣由:
系統剛上線各方面都很正常,可是因爲某種操做觸發或者運行一段時間以後出現接口卡頓,接口響應緩慢超時甚至假死等現象。
這種狀況的出現大多伴隨着系統硬件資源的使用率上升,如CPU和內存使用率忽然急劇飆升,直接翻倍甚至佔滿硬件資源。
若是出現系統剛上線應用、接口表現正常,運行一段時間以後出現卡頓緩慢現象,而日誌又沒有表現出明顯錯誤,或直接出現OOM,咱們須要使用這種排查思路:
首先查看系統硬件資源使用狀況,使用top命令可清晰查看,如圖:
這是咱們系統正常狀況下 947 進程的使用狀況,cpu使用率只有12.6 內存只有4.4,當系統出現問題的時候,咱們再看系統的使用狀況,如圖:
26608與上圖947爲同一應用,發現cpu使用率直接飆升到100 % 內存使用狀況翻倍,注意9.7是佔用虛擬機的比例,可是咱們單應用的jvm內存是不能夠跟虛擬機的直接比較的,因此短期內翻倍問題已經很大了。
這時候咱們已經能夠初步斷定jvm的內存管理出現了問題,因爲jvm的內存被不正常的對象大量搶佔致使系統運行緩慢。
同時,咱們數據中心的每臺機器都是有zabbix監控(全部的數據中心都會有硬件資源監控系統,zabbix最爲流行),咱們同時能夠提取zabbix的記錄來作驗證,如圖咱們舉例一臺:
咱們能夠很清晰的看到在10點到10點12之間內存和CPU(有公司信息就不放了)的狀況發生了急劇的增加,可是這和進入咱們系統的流量不是正常的比例,由此咱們能夠判定咱們的代碼的jvm的內存管理出現了問題,即大機率出現了內存溢出。
關於內存溢出:你們確定知道咱們java應用的對象的建立是由咱們管,可是回收大多數是由jvm經過必定的算法來實現的,如:最少使用、不可達、新生代的複製清除等等,也就是jvm會按照你現有對象佔用的新生代或老年代的內存比例決定是否進行垃圾回收,每次垃圾回收都是須要STW的,可是當對象非正常產生的時候,jvm是回收不過來的,會形成不應有的對象直接佔滿、超過jvm設置大小,形成系統運行緩慢或者OOM。
若是出現了上述狀況,咱們必須、必定要保存dump文件!
由於dump是惟一能夠反映java進程的內存狀況的文件,也只有拿到當時的dump文件咱們才能夠分析出來形成咱們本次上線的運行緩慢的緣由,操做方式如圖(測試環境):
1、執行 ps -ef | grep [應用名稱] --獲取 [pid]
2、執行 jmap -dump:format=b,file=website.dump [pid] 生成dump文件,生成時間可能較久
先拿到該應用的pid,而後藉助於jdk的jmap工具獲取dump文件。拿到dump文件以後就能夠對應用的內存狀況進行分析。
Dump文件須要藉助特殊的工具進行分析,如今比較流行的是IBM Memory Analyzer和Eclipse Memory Analysis(MAT),咱們用MAT來作演示。
這是咱們系統運行正常時的截圖,如圖:
這是咱們系統運行非正常的截圖,如圖:
在系統運行卡頓時,咱們的char,String 的對象數量以及佔用的內存空間發生了20倍的增加,同時咱們本身的一個對象產生了202萬個,一個對象的正常建立是絕對不可能出現這麼多的示例,因此能夠肯定使用該對象的地方的建立出現了問題,咱們能夠依此去代碼中查找問題。
同時Oracle的Driver對象也出現了不正常的增加,這將極大的佔據數據庫資源,致使其餘方法的數據庫鏈接出現問題。因此咱們能夠從代碼中尋找即便用了該對象,有鏈接了數據庫的地方。
同時除了這種運行變慢的,遇到OOM時,咱們也能夠經過對dump文件的分析查找到不合理佔據內存的對象,從而定位到問題代碼。
另外,若是系統變慢,咱們日誌和內存dump文件都沒看到問題以後,咱們就須要觀察Thread Dump文件,看是否有線程死鎖的問題。
正常的應用千篇一概,有趣的問題萬里挑一。