示例

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