以下是用於測試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”執行內存洩漏檢查分析:
點擊Finish按鈕後,MAT會將可疑的內存洩漏的對象都展現出來:
可以看到線程java.lang.Thread @ 0xff617e80 的main方法中,有一個本地變量佔用了96.43%的堆內存,實際內存佔用的是char[]數組,因而被檢測出來為OOM可疑的元兇。點擊紅色框中的“See stacktrace”,可以直接看到該對象所在線程的堆棧信息:
直接定位到了發生OOM的代碼所在位置,至此該示例分析完成,MAT工具本身還有其它許多的功能,這裡就不一一細說了。
閱讀更多 瘋狂架構師 的文章