概述
JVM OutOfMemoryError(OOME,內(nèi)存溢出錯誤)導(dǎo)致宕機的情況有多種,此處主要以超出堆最大值為例來說明OOME問題排查過程。
通過設(shè)置JVM相關(guān)參數(shù)可以在發(fā)生OOME時生成堆內(nèi)存的快照,以便后期分析問題。
JVM 主要參數(shù)
Debug 時用到的JVM參數(shù)有(具體值可以自己按需配置):
# 指定堆內(nèi)存最大值限制為10MB
-Xmx10M
# 指定堆快照生成路徑為 /test/dump,默認(rèn)文件名為:java_pidpid.hprof
-XX:HeapDumpPath=/test/dump
# 指定在發(fā)生OOME時生成堆快照文件
-XX:+HeapDumpOnOutOfMemoryError
OOME 宕機實驗
OOME 實驗代碼
package com.dotions;
import java.util.ArrayList;
import java.util.List;
public class OOMETest {
public static void main(String[] args) {
List<Long> list = new ArrayList<Long>();
// 通過死循環(huán)迫使內(nèi)存溢出
while(true) {
list.add(new Long(0));
}
}
}
JVM 運行參數(shù)
-Xmx10M
-XX:HeapDumpPath=C:/oome_test_dump.hprof
-XX:+HeapDumpOnOutOfMemoryError
- 堆最大內(nèi)存為10MB;
- 堆快照文件生成路徑為:C:/,文件名為:oome_test_dump.hprof
- 啟用在發(fā)生OOME時生成堆快照的配置開關(guān);
Eclipse 中的運行結(jié)果

生成的Dump文件

Dump 文件查看
(一)使用 jvisualvm 查看
jvisualvm.exe 是JDK自帶的工具,可以對堆文件進(jìn)行查看與簡單的分析,參考文檔:http://visualvm.java.net/zh_CN/gettingstarted.html。
jvisualvm.exe 在 ** {JAVA_HOME}/bin/** 目錄下,如下圖:

jvisualvm 界面

Dump 文件載入到 jvisualvm
在菜單欄中點擊 【文件】==> 【載入】,然后看到如下對話框:

先將文件類型選擇為:堆 Dump (.hprof, .)* ,再找之前OOME生成的dump文件,最后點擊【打開】按鈕進(jìn)行載入。
Dump 文件——概要信息

此處可以發(fā)現(xiàn)導(dǎo)致OOME的線程是main線程;
最大的對象是ArrayList類的實例。
Dump 文件——類信息

在此處可以發(fā)現(xiàn)Long類型的實例對象占了整個堆實例的97%以上;
Dump 文件——實例數(shù)

Dump文件——OQL控制臺查詢展示

(二)使用 jhat 命令查看
jhat (Java heap analyzes toolkit)是 JDK 自帶的 Java 堆內(nèi)容分析工具??梢酝ㄟ^ jhat 命令加載 dump 文件并啟動 HTTP 服務(wù)來瀏覽 dump 文件中的內(nèi)容。
**jhat **命令介紹:

jhat 啟動HTTP服務(wù)并加載指定dump文件:
# 指定 dump 文件路徑為:
# jhat 命令默認(rèn)端口為7000,此處指定 HTTP 服務(wù)端口為:80
jhat -port 80 c:/oome_test_dump.hprof
命令執(zhí)行結(jié)果:

此時HTTP服務(wù)已啟動成功,可以在瀏覽器中輸入地址:
http://localhost/
對 dump 文件進(jìn)行瀏覽,首頁展示如下:

對 dump 文件中實例數(shù)統(tǒng)計展示:

實驗總結(jié)
該實驗中我們可以發(fā)現(xiàn),由于代碼執(zhí)行時配置的JVM參數(shù)的限制,使得最大堆內(nèi)存空間為 10MB。
而程序是死循環(huán),且list 對象沒有釋放,導(dǎo)致JVM 在GC后無法釋放堆內(nèi)存空間,從而超過了堆內(nèi)存最大值的限制,導(dǎo)致了OOME。
在實際開發(fā)和部署是,根據(jù)實際情況來設(shè)置、調(diào)整堆內(nèi)存空間限制。
以Eclipse 運行狀態(tài)為例,如下圖:

** 生產(chǎn)環(huán)境,可以對JVM 中的各個分區(qū)分別設(shè)置對應(yīng)的空間閾值。此時 OOME 問題分析就必須對應(yīng)到具體的分區(qū)上,而不是只看堆內(nèi)存空間的最大值。**