Java內存溢出OOM使用Mat分析 Mat工具分析堆 Shallow Heap計算方法 Retained Heap計算方法

示例

package com.rumenz;

import java.util.ArrayList;
import java.util.List;

public class OutOfMemory {

    public static void main(String[] args) {
         List<UserTest> res=new ArrayList<>();
         while (true){
             res.add(new UserTest());
         }
    }
}

class UserTest{

}

VM 添加參數

-Xms20m -Xmx20m

輸出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.rumenz.OutOfMemory.main(OutOfMemory.java:11)

解釋:

通過VM參數控制JVM的堆內存大小隻有20m,程序不停的創建對象,而對象又是在堆上分配內存,一直不停的向List中添加對象,沒有垃圾回收,導致堆內存溢出(OutOfMemoryError).

Mat工具分析堆

1.下載Mat分析軟件: https://www.eclipse.org/mat/d...

2.VM參數加上: -XX:+HeapDumpOnOutOfMemoryError 開啓堆內存溢出導出堆內存到文件,默認在項目的根目錄下.如果需要指定其它路徑用 -XX:HeapDumpPath=/tmp ,會生成一個名字類似的 java_pid28790.hprof 文件.

3.使用Mat打開hprof文件

java.lang.Object[14053]含義:

List<UserTest> 本質上就是Object[]數組,14053就是裏面存放的對象的個數.

  • Shallow Heap (淺層堆)表示:對象實際佔用的堆大小(不包含其它引用對象的大小)
  • Retained Heap(保留堆)表示:對象實際佔用+所包含引用對象的大小

Shallow Heap計算方法

在本次案例中: Shallow Heap 佔用 112448 字節, Retained Heap 佔用 337296 字節.

List<UserTest> res=new ArrayList<>(); res是局部變量,在棧上分配內存,res中存放的是 UserTest 實例對象的堆內存地址(引用),JDK1.8中打開指針壓縮( -XX:+UseCompressedOops),在64位系統引用就佔4個字節,未打開指針壓縮64位系統中引用指針佔用8個字節.

當前案例未打開指針壓縮:
14053個引用地址佔用內存大小: `14053*8=112424`,`Shallow Heap`佔用`112448`字節,還有24字節明顯就是res容器本身佔用的內存大小.

數組淺堆佔用內存計算:

16 bytes of overhead 對象的頭
4 bytes length 存儲容器長度
4 bytes padding 字節對其

16 bytes of overhead + 4 bytes length + 4 bytes padding = 24 bytes

Retained Heap計算方法

Retained Heap Size=Shallow Heap Size+引用對象實際大小

Shallow Heap 已經計算出來了

引用對象的實際大小:本案例中,由於UserTest是一個空的對象,所以每個UserTest實例對象就只佔用 16字節 的對象頭.總共有14053個實例對象,所以共佔用 14053*17=224848 .

Retained Heap=112424+224848=337296和Mat分析的結果一致.

來源:https://www.tuicool.com/articles/RB732uN

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章