美文网首页
在java中new一个对象过程中发生了什么

在java中new一个对象过程中发生了什么

作者: 楼兰King | 来源:发表于2022-03-01 11:26 被阅读0次
    简述::

    1.确认类元信息是否存在,当 JVM 接收到 new 指令时,首先在 metaspace 内检查需要创建的类元信息是否存在。 若不存在,那么在双亲委派模式下,使用当前类加载器以 ClassLoader + 包名+类名为 Key 进行查找对应的 class 文件。 如果没有找到文件,则抛出 ClassNotFoundException 异常 , 如果找到,则进行类加载(加载 - 验证 - 准备 - 解析 - 初始化),并生成对应的 Class 类对象。
    2.分配对象内存。 首先计算对象占用空间大小,如果实例成员变量是引用变量,仅分配引用变量空间即可,即 4 个字节大小,接着在堆中划分—块内存给新对象。 在分配内存空间时,需要进行同步操作,比如采用 CAS (Compare And Swap) 失败重试、 区域加锁等方式保证分配操作的原子性。
    3.设定默认值。 成员变量值都需要设定为默认值, 即各种不同形式的零值。
    4.设置对象头。设置新对象的哈希码、 GC 信息、锁信息、对象所属的类元信息等。这个过程的具体设置方式取决于 JVM 实现。
    5.执行 init 方法。 初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。

    在Java中创建一个Object对象会占用多少内存?
    对象头大小应该理论上为mrakword+klassword=16bytes=128bit,同时Object类中是没有定义任何属性的,所以不存在实例数据。但如果在开启指针压缩的情况下,只会有12bytes,因为对象头中的类元指针会被压缩一半,所以会出现4bytes的对齐填充,最终不管是否开启了指针压缩,大小应该为16字节,接着来论证一下(环境:默认开启指针压缩的JDK1.8版本)
    1.maven引入OpenJDK组织提供的工具

    工具中提供了两个API:
    GraphLayout.parseInstance(obj).toPrintable():查看对象外部信息:包括引用的对象
    GraphLayout.parseInstance(obj).totalSize():查看对象占用空间总大小

    <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
    <dependency>
        <groupId>org.openjdk.jol</groupId>
        <artifactId>jol-core</artifactId>
        <version>0.9</version>
    </dependency>
    
    import org.openjdk.jol.info.ClassLayout;
    
    public class jvmtest {
        public static void main(String[] args) {
            Object a=new int[9];
            System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }
    }
    

    输出结果:


    image.png

    从结果中可以很明显的看到,0-12byte为对象头,12-16byte为对齐填充数据,最终大小为16bytes,与上述的推测无误,在开启指针压缩的环境下,会出现4bytes的对齐填充数据。

    数组对象大小计算

    上述简单分析了Object对象的大小之后,我们再来看一个案例,如下:
    public static void main(String[] args){
    Object obj = new int[9];
    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }
    此时大小又为多少呢?因为该数组为int数组,而int类型的大小为32bit/4bytes,所以理论上它的大小为:(12bytes对象头+9*4=36bytes数组空间) = 48bytes,对吗?先看看运行结果:

    image.png

    从结果中可以看出最终大小为56bytes,实际的大小与前面的推断存在明显出入,为什么呢?这是因为目前的obj对象是一个数组对象,在前面分析对象头构成的时候曾分析过,如果一个对象是数组对象,那么它的对象头中也会使用4bytes存储数组的长度,所以此时的obj对象头大小为16bytes,其中12~16bytes用于存储数组的长度,再加上9个int类型的数组空间36bytes,大小为52bytes,因为52不为8的整数倍,所以JVM会为其补充4bytes的对齐填充数据,最终大小就成了上述运行结果中的56bytes。

    相关文章

      网友评论

          本文标题:在java中new一个对象过程中发生了什么

          本文链接:https://www.haomeiwen.com/subject/bpudrrtx.html