计算Java对象占用内存空间大小

使用到的工具是lucene

<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>4.2.0</version>
</dependency>

注意版本,新版本好像不能计算一些自定义对象和集合,只能计算基本类型的数组
当一个对象没有任何属性和占用空间时,这个对象结构框架实际上也是有占用一定的空间的,那就是对象头。

Java对象内存布局

对象头(Header),实例数据(Instance Data)和对齐填充(Padding)
另外,不同环境Java对象占用内存空间可能有所差异。本文实验环境如下,HotSpot 64-Bit虚拟机,默认开启指针压缩(-XX:+UseCompressedOops),结合如图1,所以Java对象实例的对象头大小为12bytes(8bytes makOop + 4 bytes klassOop), Java数组实例的对象头大小为16bytes(8bytes makOop + 4 bytes klassOop + 4 bytes length);64位Linux系统,所以字节对齐必须是8的倍数。
可以通过java -verson查看自己当前JAVA虚拟机的版本
在这里插入图片描述

原生类型:

对于8种基本类型,他们实际上会自动封装成一个包装类型
在这里插入图片描述
则以一个int 类型的变量为例子:
int i = 1;
RamUsageEstimator.sizeOf(i)
结果为 :16
其结构为:12(Header) + 4(Instance Data)=16 bytes

12(Header) + 4(Instance Data)=16 bytes
对象头大小     int类型的值大小

如果是char类型
char c = ‘c’;
RamUsageEstimator.sizeOf©
结果为:16
但是他的结构有所不同:

12(Header) + 2(Instance Data) + 2(Padding)=16 bytes
对象头          值占用             填充

因为 12 + 2 =14不是8的倍数,所以填充占的两位是为了让结构统一的

基本类型与他们对应的实际包装类型其实是一致的。

对于null,和Object这两个特殊对象
null占0字节
Object占 16字节

数组

对于int类型数组
int[] array0 = new int[0];
int[] array1 = new int[1];
int[] array2 = new int[2];

占用情况为:
16(Header)=16 bytes
16(Header) + 4(int) + 4(Padding)=24 bytes
16(Header) + 4(int)*2=24 bytes

结构为: 对象头16 + 一个长度占用4byte长度

String

先看看源码:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
}

这里其实只需要看非静态变量,静态变量不再对象的堆内存中,不纳入计算范围
一个用于存放字符串数据的char[], 一个int类型的hashcode
所以一个String对象占用的内存空间大小为:
40 + length * 2 bytes + Padding
在这里插入图片描述
如:
String s0 = “”;
String s1 = “a”;
String s2 = “aa”;

大小为:
40 + 0 * 2 = 40 bytes
40 + 1 * 2 + 6(Padding) = 48 bytes
40 + 2 * 2 + 4(Padding) = 48 bytes

ArrayList

看看部分源码:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     */
    private int size;
}

对于非静态变量只有一个用于存放数组元素的Object[], 一个int类型的size。
因此,一个ArrayList本身需要 12(Header) + 4(Object[] reference) + 4(int) + 4(Padding) = 24 bytes。
除此之外,一个Object[]占用16(Array Header) + length * 4(Object reference) bytes(8字节对齐),length是Object[]长度,即ArrayList容量,size是ArrayList存放的元素数量,其中length >= size,另加数组初始化的Object占用的内存空间,如下图,所以一个ArrayList占用的内存空间大小为:

((40 + length * 4)(8字节对齐) + size * n bytes)(8字节对齐),假设Object对象占用n bytes,size * n表示只有在数组初始化的Object才需要分配内存空间。
在这里插入图片描述

参考:https://www.jianshu.com/p/40faea07d4d2

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值