在實際的開發過程中,我們經常遇到
java.lang.OutOfMemoryError
異常,那麼如何定位是程序的哪裏出現這個異常的呢?本博文將體驗OutOfMemoryError的定位
本博文體驗的軟件環境
JDK版本 | IDE |
---|---|
Java 1.8.0.144_x64 | IDEA 2019.1 |
- 編寫OutOfMemoryError的代碼
public class Test {
public static void main(String[] args) {
List<E> list = new ArrayList<>();
// 不斷的循環添加對象
while (true) {
list.add(new E());
}
}
}
class E {
}
- 我們打開IDEA中的VM Arguements參數的設置
然後我們在上面 VM options中輸入-XX:+HeadDumpOnOutOfMemoryError -Xms20m -Xmx20m
,下面的Working directory是生成的堆內存快照的目錄路徑
上述參數的意義:
- -XX:+HeapDumpOnOutOfMemoryError
生成堆內存的快照
- -Xms20m
爲jvm啓動時分配的內存,比如-Xms20m,表示分配20M
- -Xmx20m
設置JVM最大可用內存爲20M
-Xms和-Xmx設置一樣的,避免每次垃圾回收完成後JVM重新分配內存
- 運行該程序
我們很快就能發現,程序報java.lang.OutOfMemoryError: Java heap space
異常,在對應的目錄環境下,我們可以發現生成了 堆內存快照,每次運行都生成當前運行進程號pid對應的內存版本快照,可以根據進程號獲取對應的內存版本快照
這是一個hprof類型的文件,我們打開也是亂碼,那麼我們怎麼查看呢?
- 安裝JProfiler內存分析工具
安裝結束之後,如下圖
注意,這裏安裝的插件只是將JProfiler的入口集成到IDEA中,我們還需要下載JProfiler軟件安裝到需要本機的環境中
下載的地址:
JProfiler
安裝完成之後,我們來修改下我們的程序
public class Test {
public static void main(String[] args) {
List<E> list = new ArrayList<>();
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(new E());
}
}
}
class E {
// 讓對象有一定大小
public byte[] bytes = new byte[10 * 1024];
}
程序中的睡眠主要是爲了讓程序不會一下子結束,我們就可以點擊上面的jProfiler按鈕,進入界面觀察具體的內存情況
- 執行程序,點擊JProfiler按鈕(上面截圖的按鈕)進行如下的操作:
顯示當前程序執行的內存、CPU和GC的情況
從圖中我們其實已經看到程序已經發生了GC了
點擊【Memory】查看內存使用情況
從圖中我們可以看到我們設置的最大可用的內存情況,並且當前看到當前隨着程序運行,當使用的內存不斷增大,達到最大的可用內存時,程序就會OutOfMemoryError,我們也可以通過選擇不同的【Memory Pool】來查看不同區域的內存情況
- 我們也可以軟件來查看hprof類型的文件
之前我們配置過VM Options的參數,輸入的內存快照,如果我們想看看內存快照具體是顯示什麼內容,我們可以通過 【Memory Analyzer】這個軟件來查看
這個是本地運行來查看dump日誌的軟件
如果我們想要查看具體的程序執行情況,想要查看是哪些代碼造成內存溢出的,我們可以進行如下操作
從上圖中我們可以看到造成內存異常的主要是om.amos.tools.common.E
對象的大量創建
綜上就是我們跟蹤正常執行的和內存快照查看的具體操作,以後我們在整理JVM分析時可以用來跟蹤程序執行情況以及發生GC的主要原因