今天给大家介绍一个对象内存计算神奇。jvm内存溢出的时候,我们可以通过很多方法查看原因,很多时候也需要查看具体是哪一个大对象导致内存溢出。
这里要介绍的是lucene提供的专门用于计算堆内存占用大小的工具类:RamUsageEstimato
maven坐标:1
2
3
4
5
6
org.apache.lucene
lucene-core
4.0.0
RamUsageEstimator就是根据java对象在堆内存中的存储格式,通过计算Java对象头、实例数据、引用等的大小,相加而得,如果有引用,还能递归计算引用对象的大小。RamUsageEstimator的源码并不多,几百行,清晰可读。这里不进行一一解读了。它在初始化的时候会根据当前JVM运行环境、CPU架构、运行参数、是否开启指针压缩、JDK版本等综合计算对象头的大小,而实例数据部分则按照java基础数据类型的标准大小进行计算。思路简单,同时也在一定程度上反映出了Java对象格式的奥秘!
常用方法API:1
2
3
4
5
6
7
8
9//计算指定对象及其引用树上的所有对象的综合大小,单位字节
long RamUsageEstimator.sizeOf(Object obj)
//计算指定对象本身在堆空间的大小,单位字节
long RamUsageEstimator.shallowSizeOf(Object obj)
//计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB
String RamUsageEstimator.humanSizeOf(Object obj)
点评:使用该第三方工具比较简单直接,主要依靠JVM本身环境、参数及CPU架构计算头信息,再依据数据类型的标准计算实例字段大小,计算速度很快,另外使用较方便。如果非要说这种方式有什么缺点的话,那就是这种方式计算所得的对象头大小是基于JVM声明规范的,并不是通过运行时内存地址计算而得,存在与实际大小不符的这种可能性。
具体demo案例:1
2
3
4
5
6
7
8
9
10List list &#61; new ArrayList<>();
for(int i&#61;0;i<10;i&#43;&#43;){
OrderDTO orderDTO &#61;new OrderDTO();
orderDTO.setType(i&#43;"");
orderDTO.setCode(i&#43;"");
list.add(orderDTO);
}
System.out.println("humanSizeOf:"&#43;RamUsageEstimator.humanSizeOf(list));
System.out.println("shallowSizeOf:"&#43;RamUsageEstimator.shallowSizeOf(list));
System.out.println("sizeOf:"&#43;RamUsageEstimator.sizeOf(list));
结果&#xff1a;humanSizeOf:1.2 KB
shallowSizeOf:24
sizeOf:1280