聽阿里巴巴JVM工程師為你分析常見Java故障案例
本文根據12月23日阿里巴巴技術保障部JVM組軟體工程師陸傳勝老師的主題分享整理!小編特別整理出其中精華內容,供大家學習交流。
目錄
-
HotSpot常識
-
Java故障排查方法論
-
Java故障案例分析
Part 1
HotSpot常識
-
HotSpot是目前最常見的開源JVM(GPL協議),用來執行Java應用和applet,本次討論基本都是基於這一軟體來進行的。
-
所有的Java物件都是分配在Java堆上的,Java程式碼中看到的引用,在JVM的實現中就是一個指標,指向一段被表示成物件的記憶體區域。這個區域可能被移動,引用指標的值不同於一般的C/C++指標,是會從外部改變的。
-
執行的Java位元組碼都是動態載入、連結、編譯的。
-
JIT compiler,JVM裡面有一個模組負責把Java位元組碼編譯成優化過的native機器碼,這樣可以極大提高執行效率。
但是HotSpot的JIT編譯器只會編譯熱點方法,一個Java方法load進來後會預設從直譯器開始執行,只有部分或整體的解釋執行次數超過一定次數才會被編譯優化,在某些條件下,比如debug,會把方法去優化退回到直譯器執行。直譯器可以看做是一個沒有優化的翻譯器,會把每一條bytecode指令機械的翻譯成彙編指令來執行。
1.6, 兩個stack,interned string放到heap
這張圖裡每一個小方塊展開都可以寫一系列文章,今天就不在這裡展開了。
Part 2
Java故障排查方法論
11參考書
2幾個我個人常用的三個原則
-
從淺顯和廣泛開始。
分析問題應該儘量從高層入手,收集各種各樣的現場資訊,版本資訊,儘量不要一開始就debugger跑起。 -
分而治之,隔離問題。
將問題隔離到儘可能小的領域中,比如某個特定系統、特定版本、甚至特定機器中。之後如果是java的問題,還可以繼續分析是java應用、容器、或者jdk的問題,最後應該能確定到某個模組的某些程式碼、一次commit、一行配置的問題。整個排查問題的過程就是一個從上到下,一步步縮小問題範圍的過程。 -
福爾摩斯法則。
當排除了所有的不可能,那麼剩下的那個,不管多麼荒謬,就是罪魁禍首了。
3重現故障和收集資料
不同於其他工業系統,軟體工業的一個好處就是重新嘗試的代價一般都特別小,重啟一個程式總比重啟一臺發動機、一個核反應堆輕鬆很多。所以如果故障問題能穩定的通過重啟復現,這對於修bug的同學將會是個天大的好訊息。
但是現實中,特別是在生產環境中,更多的事後故障問題不是你想發現就能發現,經常是重啟後就沒了,跑了不確定的時間就又出現了,所以只能通過收集故障時的系統狀態資料來分析問題。狀態資料大致可以分為兩類:一是監控類資料,收集這類資料對於應用的效能影響很小,基本可以忽略不計,所以可以持續收集,比如GC log,應用log等;第二類是某些瞬時資料,這些資料要麼收集的代價很大,很影響系統效能,要麼時效性很高,過了故障點一切可能就都不一樣了,所以不能持續收集,必須迅速的在故障出現點自動採集,比如Heap dump,core dump等。
下面這個圖描述了常見的Java故障和需要收集的資料之間的概要關係
JVM級別資料
對於JVM,下面這些選項最好常年開啟選項,對於收集故障資料很有幫助
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/gcdump
系統級別資料
Java程式執行的環境資訊也是重要的診斷資訊,如果能在故障點全部收集下來對於後續除錯分析也是很有幫助的,這些資訊主要包括: 系統基本軟硬體資訊、所有程式的情況、開啟的檔案描述符等等。
簡單的做法可以在Java程式非正常返回的時候執行一個指令碼,自動的去採集一遍這些資訊。(HotSpot支援在致命錯誤或者oom時執行一個系統命令,可以設定讓其去直接執行這個指令碼)。或者說是使用一個監控程式,監視Java程式的輸出結果,如果發現異常、crash等情況,就收集一次環境資訊。
Part 3
Java故障案例分析
故障1CPU load過高
問題一般是指CPU使用率很高,但是系統並沒有很繁忙,一般有兩種情形。
情況1,啟動階段
應用剛啟動之後或者剛放了使用者流量之後,也是可能突然cpu load飆到很高的,這一般不是java程式碼引起的,而是由於jvm的jit編譯器引起的。(當然如果你使用的是一些非普遍的JDK,比如IBMJDK,並且啟用了AOT之類的功能,是不可能遇到這個情況的,因為程式碼已經提前編譯好了)
-
-XX:+TieredCompilation
可以先一定程度上減輕這個問題,效果上相當於把消耗資源嚴重的一些優化處理延後進行了,先把java方法編譯到一個低優化級別的native方法。值得注意的是,這個引數會消耗比較多的記憶體資源,同一個方法被編譯了多次,存在多份native記憶體拷貝,建議是把codecache調大一點兒(-XX:+ReservedCodeCacheSize,InitialCodeCacheSize)。
Optional:
CodeCache不足可能會引起效能問題,這是一種非常少見的故障,code cache不足,jit需要編譯新的方法的時候就會不停的嘗試清理code cache,丟棄掉無用的方法,頻繁的嘗試會導致大量資源消耗在JIT執行緒上。
-
-XX:+PrintCompilation
為了確認這個問題可以嘗試使用這個引數,輸出JIT編譯的情況,如果初始階段發生大量方法的編譯,就可以確定是由於JIT編譯引起的。一般情況下,忍一忍熬過一開始的編譯階段就好了。如果使用者請求超時嚴重,無法忍受,可以嘗試使用分層編譯、提前預熱系統。
情況2,非啟動階段
一般是一些計算密集型任務、忙等操作、或者過於密集的執行緒排程。一般需要定位出被頻繁執行的程式碼邏輯(熱點方法),然後再進行優化,目前可以使用各種profile工具來分析。比如Java Mission Control, ZProfiler(硬廣:阿里自產的profiler工具)
故障2應用效能下降/較差
這個問題又兩個層面,一個是應用的效能下降了,這一般是來自監控系統或者使用者突然的報警 。從分割問題的角度看,效能下降一般是和之前時間點比較得出的結論,那麼就肯定有一個分水嶺,在某一個時間點(通常是一個改動發生的時候)之後就會開始效能下降。所以初始的解決方案比較簡單,就是找到改動發生的時間點,挑出造成效能下降的改動,然後分析這個改動為什麼會造成效能下降。
但是如果就是一個應用效能較差的問題,就比較棘手了,這個通常意味著沒有可以比較的時間點,相當於憑空設定一個效能指標,將系統效能優化提升到這個目標。通常這是一個需要多方合作,修改多個層次的程式碼、配置才能達到的目標。通常而言可以繼續嘗試profiling Java應用,分析效能瓶頸,優化瓶頸部分。
可能有影響的瓶頸包括:
鎖
這個一般需要設計、程式碼層面的改動,使用更高效的加鎖機制,減輕競爭,等等。
GC
頻繁full gc的又有兩種情況,一種是說full gc完了之後整個heap還是沒有很多的可用空間,一般是可能是由於最大heap上限可能設定有點兒小了,或者應用有記憶體洩露,需要做個heap dump具體分析下記憶體裡面各個部分的使用情況。
另外一個情況是full gc完了之後整個heap還是有不少的可用空間的,比如下圖,這個一般是有一些“臨時”物件晉升到了老年代,新生代沒有濾掉足夠的短生命週期物件,可能需要調整JVM引數-XX:MaxTenuringThreshold(15, 4bits)提高promote到老年代的門檻。
分析GC日誌,一個開源的免費解決方案是eclipse的GCMV
GC引數優化
關於GC其實你能做的並不多,影響最大就是通過調整JVM啟動時引數,來調節GC的各個行為,
1. 仔細設計一個適合你自己環境、應用的引數模板。
2. 收集應用資訊,評估應用記憶體活動行為(參見“Java效能優化權威指南”),常駐記憶體物件大小,大物件比例,native記憶體使用,分配速度等。。。
3. 調整下列引數(不是一條命令哦)
-Xms8888m
-Xmx8888m
-Xmn8888m
-Xss8888k
-XX:PermSize=8888m
-XX:MaxPermSize=8888m
-XX:+UseStringCache
-XX:+UseConcMarkSweepGC
-XX:+UseG1GC
-XX:+UseParNewGC
-XX:ParallelGCThreads=8888
-XX:+CMSClassUnloadingEnabled
-XX:+DisableExplicitGC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=88
GC停頓時間太長
堆太大的時候,CMS GC可能會停頓比較久的時間,-XX:+CMSScavengeBeforeRemark能通過在remark階段前做一次young gc減輕這個時間。
另外可以考慮換G1。
故障3記憶體耗盡OOM
基本的解決思路,多給點兒或者少用點兒唄。
-
Java物件真的耗盡了記憶體資源,Eclipse MAT
HeapDump,分析記憶體洩露,大物件,物件關係圖。 -
Native記憶體耗盡, DirectBuffer,malloc
JVM執行過程中,雖然會對Java堆做垃圾收集,但是如果jni或者非DirectBuffer的Unsafe分配的記憶體沒有回收,會逐漸累積直至java程式結束。DirectBuffer雖然Java物件很小,但是使用的記憶體可能會很多。
-
PermGen耗盡,一般動態類載入導致,已經成為歷史,儘早升級吧。
故障4崩潰crash
現代JVM發展到今天已經很健壯了,一般很少會出現crash的情況,如果出現了,很有可能是Java程式碼執行了不安全的操作,比如使用Unsafe去直接操作記憶體、自己編寫了JNI函式中crash了。
目前的現實是很多第三方的庫確實直接使用了Unsafe去實現各種“高效”的操作,隨便搜尋下Github就可以看到大量的開源Java、Scala庫使用了JDK提供的unsafe類
對於crash的情形,需要收集的資訊包括各種dump,最關鍵的是系統core dump,方便將來使用GDB做事後分析,在linux上一般需要使用ulimit –c unlimited 命令修改core檔案尺寸上限才行。
有了core dump,剩下的分析一般都是使用GDB繼續了,crash的情形一般反而比較直觀。如果不是unsafe、自己jni引起的crash問題,恭喜你,真的發現bug了,這個問題直接給Oracle或者java社群報bug吧。
指令碼太複雜,怎麼知道最後跑起來的Java程式到底設定了哪些引數?
-XX:-PrintCommandLineFlags
Q & A
Q1:關於記憶體洩露,是不是可以用一些開源產品來加探針,這方面有沒有好的建議?
A1:記憶體洩露其實有兩個方面,如果是native的malloc洩露,可以通過 valgrind,jemalloc等工具發現,這個和傳統c++應用記憶體一樣的;對於某些因為強引用鏈無法釋放的java物件,一般都是 heapdump之後使用eclipse的mat工具分析“可能洩露的”,因為程式並沒有結束,而且還持有強引用,很難得出結論說某些物件是不是記憶體洩露。
Q2:關於記憶體洩露, 怎麼定位到具體程式碼?
A2:定位到程式碼目前比較可行的,就是用MAT分析出那些型別的物件發生了洩露,然後去掃描程式碼看看這些物件在哪裡分配的,當然如果大量的string,byte.就不好辦了,一般是以使用者應用自定義的類為線索去查詢。這樣可以大大降低工作量。
講師介紹:陸傳勝
-
現就職於阿里巴巴技術保障部JVM組,主要工作是阿里巴巴定製化JDK的開發, 以及相關的Java技術支援。
-
曾就職於IBM Java技術中心,負責IBMJDK開發、參與OpenJDK社群,是OpenJDK jdk8專案committer。
-
聯絡方式chuanshenglu@gmail.com
本文來自雲棲社群合作伙伴”DBAplus”,原文釋出時間:2015-12-25
相關文章
- cpu故障現象分析 CPU常見故障案例
- 0.java開發常見故障Java
- Oracle RAC常見啟動失敗故障分析Oracle
- JVM之調優及常見場景分析JVM
- [jvm]常見的oom異常JVMOOM
- 程式排程案例分析與常見疑惑1:為何不能排程?
- Java常見知識點彙總(⑮)——Jvm架構JavaJVM架構
- ORACLE 常見故障恢復Oracle
- 常見的JVM 面試題JVM面試題
- Oracle RAC Database 11.1.0.6監聽故障案例OracleDatabase
- 故障分析 | MySQL死鎖案例分析MySql
- JVM常見引數設定JVM
- 常見電腦硬碟故障彙總 常見電腦硬碟故障的解決辦法硬碟
- 聽說你也想學 Composer----常見命令手冊
- 汽車自動變速器的三個常見故障原因分析
- 資料庫監聽夯故障分析資料庫
- Java常見異常彙總 這些“攔路虎”你遇見了嗎?Java
- Oracle 常見故障及日常規劃Oracle
- Java開發工程師常見的面試總結走起.....Java工程師面試
- Flutter 常見異常分析Flutter
- 常見JVM基礎面試必備JVM面試
- 常見硬碟故障大全 硬碟故障解決辦法大全硬碟
- 你的Redis為什麼變慢了?常見延遲問題定位與分析Redis
- 電腦主機板維修例項 主機板常見故障分析
- 專案管理的一個案例,聽聽大家的意見專案管理
- 好程式設計師Java教程分享:Java工程師常見面試題程式設計師Java工程師面試題
- 印表機的常見故障解決方法 HP 5000印表機為例
- Oracle 修改預設監聽埠故障分析Oracle
- k8s-----常見故障及解析K8S
- DVR常見故障原因及解決方法VR
- 筆記本常見故障與排除方法筆記
- 常見故障之八:JDBC Connection PoolsJDBC
- 常見的網路故障排除辦法
- 【效能測試】常見的效能問題分析思路(二)案例&技巧
- 利用 Java dump 進行 JVM 故障診斷JavaJVM
- 膝上型電腦常見顯示卡故障導致電腦問題分析
- jvm系列:Java GC 分析JVMJavaGC
- 讓你聽見的 HTML5HTML