java 对象的内存布局

环境: 本机为64位操做系统。jdk 1.8数组

1、对象在内存中存储的布局能够分为3块区域:对象头(Header),实例数据(Instance Data),对齐填充(Padding)。ruby

2、咱们能够经过maven工程引用对应的 jol-core jar包。将对应的内存分布打印出来作相应的研究。架构

      我这里写勒一个类:User,4个字段 占用 4*4 byte =16 byte 共16字节 (实例数据占用16字节)并发

  

        ObjectHeader类的打印对象的总体分布:主要代码以下:jvm

        System.out.println(ClassLayout.parseInstance(user).instanceSize());maven

        System.out.println(ClassLayout.parseInstance(user).toPrintable());ide

产生结果:oop

上图中:能够看到,对象在内存中分为3块区域。 对齐填充 在JVM中定义为 8byte 的 整数倍。 因此 28 % 8 =4 因此须要padding 4 byte 。布局

Header包含以下内容:主要由 Mark World (8byte)+ Class Pointer (4byte) (类型指针)优化

1. Mark World  根据  对象 lock 标记的状态不一样 , 所存储的内容也会发生改变. 具体以下图.


|------------------------------------------------------------------------------|--------------------|
|                                  Mark Word (64 bits)                         |       State        |
|------------------------------------------------------------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |       Normal       |
|------------------------------------------------------------------------------|--------------------|
| thread:54 |       epoch:2        | unused:1 | age:4 | biased_lock:1 | lock:2 |       Biased       |
|------------------------------------------------------------------------------|--------------------|
|                       ptr_to_lock_record:62                         | lock:2 | Lightweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                     ptr_to_heavyweight_monitor:62                   | lock:2 | Heavyweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                                                                     | lock:2 |    Marked for GC   |
|------------------------------------------------------------------------------|--------------------|
biased_lock lock 状态
0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁
0 11 GC标记

lock:2位的锁状态标记位,因为但愿用尽量少的二进制位表示尽量多的信息,因此设置了lock标记。该标记的值不一样,整个mark word表示的含义不一样。 biased_lock:对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。
age:4位的Java对象年龄。在GC中,若是对象在Survivor区复制一次,年龄增长1。当对象达到设定的阈值时,将会晋升到老年代。默认状况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。因为age只有4位,因此最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的缘由。
identity_hashcode:25位的对象标识Hash码,采用延迟加载技术。调用方法System.identityHashCode()计算,并会将结果写到该对象头中。当对象被锁定时,该值会移动到管程Monitor中。
thread:持有偏向锁的线程ID。
epoch:偏向时间戳。
ptr_to_lock_record:指向栈中锁记录的指针。
ptr_to_heavyweight_monitor:指向管程Monitor的指针。

2. Class Pointer (类型指针) 这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM经过这个指针肯定对象是哪一个类的实例。该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。
若是应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64位的JVM将会比32位的JVM多耗费50%的内存。为了节约内存能够使用选项+UseCompressedOops开启指针压缩,其中,oop即ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:

  1. 每一个Class的属性指针(即静态变量)
  2. 每一个对象的属性指针(即对象变量)
  3. 普通对象数组的每一个元素指针

 上例证:

禁用指针压缩: -XX:-UseCompressedOops

开启指针压缩,jvm默认开启

固然,也不是全部的指针都会压缩,一些特殊类型的指针JVM不会优化,好比指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。

3. 若是对象是一个数组,那么对象头还须要有额外的空间用于存储数组的长度,这部分数据的长度也随着JVM架构的不一样而不一样:32位的JVM上,长度为32位;64位JVM则为64位。64位JVM若是开启+UseCompressedOops选项,该区域长度也将由64位压缩至32位

相关文章
相关标签/搜索