線上故障排查(2) - Java應用故障之堆溢位OOM問題及排查方案
以下是用於測試OOM的測試程式碼:
public class HeapMemUseTest { public static void main(String[] args) { StringBuilder sb = new StringBuilder(); while(true) { sb.append(System.currentTimeMillis()); } } }
這段程式碼非常簡單,其目的就是為了模擬OOM,將其編譯後,通過以下命令執行:
java -Xmx10m -Xms10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./oom.out HeapMemUseTest
其中的引數代表的意義為:
-Xmx和-Xms分別是用於指定該Java程序初使化的最小堆記憶體以及可以使用的最大堆記憶體的,這裡設定為10M
-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath引數分別用於指定發生OOM是否要匯出堆以及匯出堆的檔案路徑
該命令一執行,立即就會發生OOM,並列印如下的日誌:
fenglibin@fenglibin-HP:~/eclipse_neon_workspace/Test/bin$ java -Xmx10m -Xms10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./oom.out HeapMemUseTest java.lang.OutOfMemoryError: Java heap space Dumping heap to ./oom.out ... Heap dump file created [5513523 bytes in 0.027 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:700) at java.lang.StringBuilder.append(StringBuilder.java:214) at HeapMemUseTest.main(HeapMemUseTest.java:13)
檢視當前路徑,oom.out檔案已經生成了,該檔案就是應用在發生OOM異常時自動匯出的堆檔案。那我們此時需要對該檔案進行分析,因為其中記錄了是什麼物件匯出了應用程OOM的發生。
分析OOM的工具推薦使用MAT,下載地址為ofollow,noindex" target="_blank">https://projects.eclipse.org/projects/tools.mat ,在配置好Java環境的電腦中,直接開啟即可,不需要安裝,然後通過MAT開啟已經生成的OOM檔案oom.out,出現如下提示,選擇“Leak Suspects Report”執行記憶體洩漏檢查分析:
點選Finish按鈕後,MAT會將可疑的記憶體洩漏的物件都展現出來:
可以看到執行緒java.lang.Thread @ 0xff617e80 的main方法中,有一個本地變數佔用了96.43%的堆記憶體,實際記憶體佔用的是char[]陣列,因而被檢測出來為OOM可疑的元凶。點選紅色框中的“See stacktrace”,可以直接看到該物件所線上程的堆疊資訊:
直接定位到了發生OOM的程式碼所在位置,至此該示例分析完成,MAT工具本身還有其它許多的功能,這裡就不一一細說了。
下一篇會寫伺服器由於時間戳不一致,導致有些伺服器可以訪問,有些伺服器卻不能夠訪問的問題,如果感興趣,請繼續觀注。