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