Java應用故障之堆溢出OOM問題及排查方案

以下是用於測試OOM的測試Java代碼:

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
\tat java.util.Arrays.copyOf(Arrays.java:3332)
\tat java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
\tat java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:700)
\tat java.lang.StringBuilder.append(StringBuilder.java:214)
\tat HeapMemUseTest.main(HeapMemUseTest.java:13)

查看當前路徑,oom.out文件已經生成了,該文件就是應用在發生OOM異常時自動導出的堆文件。那我們此時需要對該文件進行分析,因為其中記錄了是什麼對象導出了應用程OOM的發生。

分析OOM的工具推薦使用MAT,下載地址為https://projects.eclipse.org/projects/tools.mat,在配置好Java環境的電腦中,直接打開即可,不需要安裝,然後通過MAT打開已經生成的OOM文件oom.out,出現如下提示,選擇“Leak Suspects Report”執行內存洩漏檢查分析:

線上故障排查(2) - Java應用故障之堆溢出OOM問題及排查方案

​點擊Finish按鈕後,MAT會將可疑的內存洩漏的對象都展現出來:

線上故障排查(2) - Java應用故障之堆溢出OOM問題及排查方案

​可以看到線程java.lang.Thread @ 0xff617e80 的main方法中,有一個本地變量佔用了96.43%的堆內存,實際內存佔用的是char[]數組,因而被檢測出來為OOM可疑的元兇。點擊紅色框中的“See stacktrace”,可以直接看到該對象所在線程的堆棧信息:

線上故障排查(2) - Java應用故障之堆溢出OOM問題及排查方案

直接定位到了發生OOM的代碼所在位置,至此該示例分析完成,MAT工具本身還有其它許多的功能,這裡就不一一細說了。


分享到:


相關文章: