0
点赞
收藏
分享

微信扫一扫

计算一个对象在堆中的大小

Sophia的玲珑阁 2021-09-21 阅读 74

对象的内存布局

示例

使用Unsafe类来获取对象的大小。

点评:使用Unsafe可以完全不care对象内的复杂构成,可以很精确的计算出对象头的大小(即第一个字段的偏移)及每个字段的偏移。缺点是Unsafe通常禁止开发者直接使用,需要通过反射获取其实例,另外,最后一个字段的大小需要手工计算。其次需要手工写代码递归计算才能得到对象及其所引用的对象的综合大小,相对比较麻烦。

public class CalculateObjectSize {
    private static class User{
        private int id;
        private String name;
        private int age;
        private User friend;

        public User(){}

        public User(int id,String name,int age){
            this.id=id;
            this.name=name;
            this.age=age;
            this.friend=new User();
        }
    }

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);

        User user=new User(1,"xhl",23);
        System.out.println("id起始偏移量:"+unsafe.objectFieldOffset(user.getClass().getDeclaredField("id")));
        System.out.println("name起始偏移量:"+unsafe.objectFieldOffset(user.getClass().getDeclaredField("name")));
        System.out.println("age起始偏移量:"+unsafe.objectFieldOffset(user.getClass().getDeclaredField("age")));
        System.out.println("friend起始偏移量:"+unsafe.objectFieldOffset(user.getClass().getDeclaredField("friend")));

        while (true);//这里用jps jinfo来查看参数是否设置成功
    }
}

问题1:对象头大小

答案

答:若开启类指针压缩则类指针大小位4Bytes,此时对象头大小为8+4=12Bytes,否则为8+8=16Bytes。

验证

-XX:+
UseCompressedClassPointers开启(默认也是开启的),忽略图中的Jdk-15,实际运行是Jdk-8

此时的内存布局大概是这样:

-XX:-UseCompressedClassPointers(关闭),id的起始偏移量变成了16。

此时的内存布局大概是这样:

问题2:对象实例数据大小

答案

答:若开启普通对象指针压缩则每个引用类型指针大小为4Bytes,此时实例数据大小为4+4+4+4=16Bytes,否则:4+4+8+8=24Bytes。

验证

开启普通对象指针压缩:-XX:+UseCompressedOops(默认也是开启的)oops: ordinary object pointer


通过计算(28-24)可得出name引用变量的大小为4Bytes。

关闭普通对象指针压缩:-XX:-UseCompressedOops

通过计算(32-24)可得出name引用变量的大小为8Bytes。

如下图:对象的大小为4*8=32Bytes

如下图:对象的大小为5*8=40Bytes。

也可以开一个关一个试试。

最后

1、CompactFields在Jdk14中被弃用了。

-XX:+/-CompactFields was deprecated in version 14.0 and will likely be removed in a future release.

2、实际上一个对象占用的内存不止这么大,因为它有的字段是引用类型,引用类型还引用其他的对象,这样就更大了。但从字面上理解,这些不算这个对象的内容。

举报

相关推荐

0 条评论