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