关于java:Java内存溢出OOM使用Mat分析

11次阅读

共计 1463 个字符,预计需要花费 4 分钟才能阅读完成。

示例

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 剖析的后果统一.

正文完
 0