JVM系列:对象的创建和访问

Posted 智猿其说

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM系列:对象的创建和访问相关的知识,希望对你有一定的参考价值。

一 对象的创建

Java语言是一门面向对象语言,在程序运行过程中无时无刻都有新的对象被创建出来。在Java程序中,创建对象的方式有多种,除了最常用的new关键字外,我们还可以通过反射机制、Object.clone 方法、反序列化以及 Unsafe.allocateInstance方法来新建对象。

其中,Object.clone方法和反序列化通过直接复制已有的数据,来初始化新建对象的实例字段。Unsafe.allocateInstance方法则没有初始化实例对象字段。而new语句和反射机制则是通过调用构造器来初始化实例字段。

我们通过最常用的new关键字新建对象时,虚拟机新建对象时需要经历下面几个步骤:

1.1 类加载检查

当JVM检测到一条new指令时,首先先检查该参数是否在常量池中定位到一个类的符号引用,并检查这个类的符号引用代表的类是否已被加载、解析和初始化。如果存在的话,JVM将直接使用已有的信息对该类进行操作。

如果没有,则执行相应的类加载过程。

1.2 分配内存

类加载检查通过后,虚拟机为新生对象分配内存,对象所需内存大小在类加载完成后就可以完全确定,为对象分配空间就是从Java堆中划分一块大小确定的内存。

不同的JVM垃圾收集器在分配内存时表现也不相同,具体表现有两种:

  1. 如果垃圾收集器选择的是基于压缩整理算法的,那么内存是规整的。所有用过的内存在一边,没有使用的在另一边,中间放着一个指针作为分界点的指示器。

  2. 如果垃圾收集器选择的是基于标记-清除算法的,那么内存不是规整的。已使用的内存和未使用的内存相互交错,虚拟机维护一个列表,记录哪些内存是可用的以及内存块的位置和大小。

1.3 必要的设置

内存分配结束后,虚拟机将分配到的内存空间都初始化为零值(不包括对象头),这一步保证了对象的实例字段在Java代码中可以不用赋初始值就可以直接使用,程序能访问到这些字段的数据类型所对应的零值。

其次是对对象进行必要的设置,例如对象是哪些类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等(这个后面垃圾收集时再细说)信息。这些信息存放在对象的对象头之中。

1.4 初始化对象

当完成上述操作后,对象的内存分配成功了,但所有的字段都还是零值。此时会执行<init>方法,把对象按照代码所写的那样进行初始化,从而产生一个真正可用的对象。

二 对象的内存布局

对象的内存布局可以分为三个区域:对象头、实例数据、对齐填充。

  1. 对象头:非固定的数据结构。一来是用来存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。二来是类型指针(对象指向它的元数据的指针),JVM通过这个指针来确定该对象是哪个类的实例对象,如果对象是一个Java数组,对象头中还需要有一块用来记录数组长度的数据。

  2. 实例数据:存储对象真正有效的数据,也就是程序代码中定义的各种类型的字段内容。不论是从父类继承的,还是子类定义的。这部分的存储顺序会受到Java源码中的定义顺序的影响。

三 对象的访问方式

对象的访问在Java中无处不在,是最普通的程序行为,但即使是最简单的访问,也会涉及Java栈、Java堆、方法区这三个最重要内存区域之间的关联关系,如下面的这句代码:

Object obj = new Object();

由于reference类型在Java虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。

3.1 使用句柄

3.2 直接指针

使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,对于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。

我们使用最多的主流虚拟机Sun HotSpot就是使用的直接指针的方式进行对象访问的。

四 总结

本章主要讲解了对象的创建过程、在堆内存中的存储结构和访问方式,通过对象的访问我们可以把前面讲解的JVM内存模型中的方法区、堆、栈这三者关联起来,之间相互配合完成对象的创建及访问。


以上是关于JVM系列:对象的创建和访问的主要内容,如果未能解决你的问题,请参考以下文章

JVM进阶之字节码指令解析(中篇)

Jvm(46),指令集----对象创建与访问指令

JVM,看这个系列就够了

JVM系列之类加载

jvm系列:java类的加载机制

jvm系列:java类的加载机制