zoukankan      html  css  js  c++  java
  • 你的java对象占了多大的内存?

    刚开始学习java的时候,知道了继承的概念,子类会继承父类的属性,private和default(不在一个包时)的除外。当时不明白父类和子类是怎么保存属性的值,但是了解了JOL后,终于有机会解开这个长时间困扰心头的问题。

    首先,网上有一种说法,当你创建一个子类对象的时候会同时创建一个父类对象,并且子类对象会有一个指针指向父类的对象,对于这个说法我表示怀疑,因为这样的话,那你创建一个对象的时候会有很多对象创建出来,这种设计方式太浪费内存。今天就来用JOL验证一下是否是这样的。(注:本次实验的对象大小是建立在指针压缩的情况下的,指针不压缩时不影响本实验的结果,只是对象的大小不同)

    首先,你需要导入JOL包

    <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
    </dependency>
    

      之后我们先看第一个问题:一个Object类对象占用多大的内存

    public class JolTest {
        public static void main(String[] args) {
            Object o = new Object();
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
    

      执行上面的代码结果如下

     可以看到一个Object占有16个字节,前12个字节是对象头,后4个字节是java为了对齐使用的补充数据,一个java对象的大小总是8的整数倍

    之后我们尝试创建一个类,包含一个int型的变量,看看它的对象在内存中是什么样的

    public class JolTest {
        public static void main(String[] args) {
            Object o = new Parent();
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
    
    class Parent{
        private int age;
    }

    执行结果如下

    仍然是16个字节,但是不同的是12-15这4位不在是alignment,而是int,我们知道int类型占有4个字节

    之后我们写一个类继承Parent,看看它的情况

    public class JolTest {
        public static void main(String[] args) {
            Object o = new Child();
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
    class Parent{
        private int age;
    }
    class Child extends Parent{
        private int age;
    }

     从执行结果中我们可以看出,子类中拥有一个对象Parent.age,并没有指向父类的指针,因此我们可以得出结论,创建子类对象时只会得到一个子类的对象,但是子类对象中会包含父类的属性,即使该属性是private的,即使该属性和父类的属性同名

    最后我们来使用byte类型替代int来试一下结果是否有所不同,我们知道byte类型占据一个字节,我们在创建一个Child的子类

    public class JolTest {
        public static void main(String[] args) {
            Object o = new Last();
    System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
    
    class Parent{
        private byte age;
        private byte sex;
    }
    
    class Child extends Parent{
        private byte age;
    }
    
    class Last extends Child{
        private boolean sex;
    }

    执行程序,结果如下:

     我们注意到一点,当父类的属性不足4个字节时,会在后面加上alignment,我们称之为类内属性对齐(顺带一提,关闭指针压缩时,类内属性对齐将不是4个字节为单位,而是8个字节)。

    现在不知得到了我想要的答案,而且有额外的以下三种收获:

    1.如何计算一个对象的大小(启用指针压缩时):((12 + 自己属性的大小 + 自己所有祖先类的属性的大小 + 4)/ 8) * 8,自己属性的大小计算方式是:((属性的大小 + 3) / 4 ) * 4,祖先类的属性大小为每个祖先的大小之和(计算内属性对齐);以最后的代码为例,new Parent的时候占用的内存大小为 ((12 +(( 2 + 3)/4) * 4 + 4) / 8) * 8 = 18,new Child: ((12 + ((2 + 3)/ 4) * 4 + ((1 + 3)/4) * 4  + 4) / 8) *8 = 24;同样可得new Last占用的字节也是24位。至于关闭指针压缩的公式,大家理解了公式后可以自行推到出来,需要注意的就是此时类内属性对齐是8个字节为一组。

    2.另一个不支持深度继承的依据,不会使用的父类属性也会对对象的大小造成影响。

    3.在需要严格控制的对象(一般是在项目中会大量创建的类对象)中,是使用继承还是组合需要考虑一下,毕竟继承可能会浪费属性,而组合会浪费对象头和alignment,如果仅从对象大小来考虑,如果继承的属性存在必要的,建议使用继承;如果全都是非必要的,可以使用组合,在需要该属性的时候再创建对象。

  • 相关阅读:
    用互不相同的fib数列的数分解任意整数。
    2015 初赛TG 错题解析
    【模板】判断二叉查找树
    【初赛】完善程序题解题技巧 && 近六年PJ完善程序真题解析
    [NOIP 2012普及组 No.2] 寻宝
    [NOIP 2012普及组 No.1] 质因数分解
    [NOIP 2013普及组 No.4] 车站分级
    [NOIP 2013普及组 No.3] 小朋友的数字
    [NOIP 2013普及组 No.2] 表达式求值
    [NOIP 2013普及组 No.1] 计数问题
  • 原文地址:https://www.cnblogs.com/fiftyonesteps/p/12554104.html
Copyright © 2011-2022 走看看