Java对象与JVM(二)

Java对象在Java虚拟机中的内存布局


       在前面《Java对象在Java虚拟机中的创建过程》文章了解到Java对象实例是如何在Java堆中创建的。

       下面我们详细了解Java普通对象创建后,在HotSpot虚拟机Java堆中的内存布局是怎样的,可以分为3个区域:对象头(Header)、实例数据(Instance)和对齐填充(Padding)。

1、对象头

      可以主要分为两部分:

(A)、存储对象自身运行时数据

      称为"Mark Word";

      包括哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等;

      这部分长度为32bit(32位JVM)或64bit(64位JVM);

      被设计成一个非固定的数据结构,会根据对象的状态复用自己的存储空间,以便在极小的空间内存储尽量多信息;

      例如,32bit的Mark Word在未被锁定状态下,前25bit存储对象哈希码,4bit存储对象分代年龄,2bit存储锁标志位,1bit固定为0,如图所示

(B)、存储指向对象类型数据的指针

      通过这个指针确定这个对象是哪个类的实例

      不是必须的,看对象的访问定位方式:

      对HotSpot虚拟机来说,由于JVM栈本地变量表中对象的reference类型引用使用直接指针,该指针指向堆内存中的对象,所以对象头中是需要存储它的类元数据指针,该指针指向方法区中对象类型数据。

(C)、如果是Java数组,对象头还需要存储数组长度

      因为数组对象类型数据中没有数组长度信息;

      JVM可以通过普通Java对象的类元数据信息确定对象大小

                

      在HotSpot虚拟机源码"markOop.hpp"注释中,对对象头信息存储有明确的说明

            // Bit-format of an object header (most significant first, big endian layout below):
            //
            // 32 bits:
            // --------
            // hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
            // JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
            // size:32 ------------------------------------------>| (CMS free block)
            // PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
            //
            // 64 bits:
            // --------
            // unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
            // JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
            // PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
            // size:64 ----------------------------------------------------->| (CMS free block)
            //
            // unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
            // JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
            // narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
            // unused:21 size:35 -->| cms_free:1 unused:7 ------------------                     

       不同锁标志说明如下:

            //
            // [ptr | 00] locked ptr points to real header on stack
            // [header | 0 | 01] unlocked regular object header
            // [ptr | 10] monitor inflated lock (header is wapped out)
            // [ptr | 11] marked used by markSweep to mark an object
            // not valid at any other time

2、实例数据

       对象真正存储的有效信息;

      程序代码所定义的各种类型字段内容,以及包括父类继承或子类定义的

                

存储顺序:

       受到JVM分配策略参数(FiedAllocationStyle)和字段在Java源码中定义顺序影响;

       JVM默认分配策略为:longs/double、ints、short/char、boolean、oops(Ordiary Object Pointers);

       VM默认分配策略使得,相同宽度的字段总被分配到一起;

       这个前提下,父类定义的变量出现在子类之前;

       如果虚拟机的"CompactFields"参数为true,子类中较窄的变量可能插入到父类变量空隙中,以压缩节省空间

3、对齐填充

       不是必然存在的;

       只起占位符作用,没有其他含义;

       HotSpot虚拟机要求对象大小必须是8字节的整数倍;

       对象头是8字节整数倍,所以填充是对实例数据没有对齐的情况来说的

 

       到这里,我们大体了解Java对象在HotSpot虚拟机中的内存布局, 后面我们将分别去了解:对象的访问定位、方法的调用与执行、JIT编译、以及JVM垃圾收集相关内容……

 

【参考资料】

1、《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版 第2章

2、《The Java Virtual Machine Specification》Java SE 8 Edition:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

3、《Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide》:http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/index.html

4、《Memory Management in the Java HotSpot™ Virtual Machine》:http://www.oracle.com/technetwork/java/javase/tech/memorymanagement-whitepaper-1-150020.pdf

5、HotSpot虚拟机参数官方说明:http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐