为什么要学习Java对象头

学习Java对象头主要是为了解synchronized底层原理,synchronized锁升级过程,Java并发编程等。

JAVA对象头

由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能,这些标记字段组成了对象头。

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding)。

也就是说 JAVA对象 = 对象头 + 实例数据 + 对象填充。

其中,对象头由两部分组成,一部分用于存储自身的运行时数据,称之为 Mark Word,另外一部分是类型指针,及对象指向它的类元数据的指针。

对象头 = Mark Word + 类型指针

(未开启指针压缩的情况下)

在32位系统中,Mark Word = 4 bytes = 32 bits,对象头 = 8 bytes = 64 bits;

在64位系统中,Mark Word = 8 bytes = 64 bits ,对象头 = 16 bytes = 128bits;

bytes 是字节,bits 是位。所以说,在32位JVM虚拟机系统中,Mark Word部分,占了4个字节,Klass Word部分也占了4个字节,所以,对象头大小为8个字节。在64位JVM虚拟机系统中,Mark Word部分,占了8个字节,Klass Word部分也占了8个字节,所以,对象头大小为16个字节。

32位虚拟机对象头

32位虚拟机普通对象的对象头

|-----------------------------------------------------------|
| Object Header (64 bits) |
|---------------------------------|-------------------------|
| Mark Word (32 bits) | Klass Word (32 bits) |
|---------------------------------|-------------------------|

32位虚拟机数组对象的对象头

|---------------------------------------------------------------------------------|
| Object Header (96 bits) |
|--------------------------------|-----------------------|------------------------|
| Mark Word(32bits) | Klass Word(32bits) | array length(32bits) |
|--------------------------------|-----------------------|------------------------|

32位虚拟机对象头详情如下

|--------------------------------------------------------------------------------------------------------------|
| Object Header(64bits) |
|--------------------------------------------------------------------------------------------------------------|
| Mark Word(32bits) | Klass Word(32bits) | State |
|--------------------------------------------------------------------------------------------------------------|
| hashcode:25 | age:4 | biased_lock:0 | 01 | OOP to metadata object | Nomal |
|--------------------------------------------------------------------------------------------------------------|
| thread:23 | epoch:2 | age:4 | biased_lock:1 | 01 | OOP to metadata object | Biased |
|--------------------------------------------------------------------------------------------------------------|
| ptr_to_lock_record:30 | 00 | OOP to metadata object | Lightweight Locked |
|--------------------------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:30 | 10 | OOP to metadata object | Heavyweight Locked |
|--------------------------------------------------------------------------------------------------------------|
| | 11 | OOP to metadata object | Marked for GC |
|--------------------------------------------------------------------------------------------------------------|

64位虚拟机对象头

|--------------------------------------------------------------------------------------------------------------|
| Object Header(128bits) |
|--------------------------------------------------------------------------------------------------------------|
| Mark Word(64bits) | Klass Word(64bits) | State |
|--------------------------------------------------------------------------------------------------------------|
| unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| 01 | OOP to metadata object | Nomal |
|--------------------------------------------------------------------------------------------------------------|
| thread:54| epoch:2 |unused:1|age:4|biase_lock:1| 01 | OOP to metadata object | Biased |
|--------------------------------------------------------------------------------------------------------------|
| ptr_to_lock_record:62 | 00 | OOP to metadata object | Lightweight Locked |
|--------------------------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:62 | 10 | OOP to metadata object | Heavyweight Locked |
|--------------------------------------------------------------------------------------------------------------|
| | 11 | OOP to metadata object | Marked for GC |
|--------------------------------------------------------------------------------------------------------------|

lock:2位的锁状态标记位,由于希望用尽可能少的二进制位表示尽可能多的信息,所以设置了lock标记。该标记的值不同,整个mark word表示的含义不同。

biased_lock lock 状态
0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁
0 11 GC标记

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的指针。

如何查看对象头

查看对象头,就需要用到借助JOL工具。

<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import static java.lang.System.out; public class TestBiased {
public static void main(String[] args) {
Dog d= new Dog();
//打印JVM的详细信息
out.println(VM.current().details());
//打印对应的对象头信息
out.println(ClassLayout.parseInstance(a).toPrintable());
}
} class Dog {
}

打印,大概如下。

21:46:08.204 c.TestBiased [main] - # Running 64-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 21:46:08.215 TestBiased [main] - cn.itcast.test.Dog object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 50 c8 e1 3f (01010000 11001000 11100001 00111111) (1071761488)
12 4 (object header) 71 01 00 00 (01110001 00000001 00000000 00000000) (369)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

如果打印不一样,可以加VM options参数-XX:-UseCompressedOops,关闭指针压缩。

要看懂VALUE这串数还得了解一下小端存储

一个对象创建时:

如果开启了偏向锁(默认开启),那么对象创建后,markword 值为 0x05 即最后 3 位为 101,这时它的

thread、epoch、age 都为 0

偏向锁是默认是延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加 VM 参数

-XX:BiasedLockingStartupDelay=0 来禁用延迟

如果没有开启偏向锁,那么对象创建后,markword 值为 0x01 即最后 3 位为 001,这时它的 hashcode、

age 都为 0,第一次用到 hashcode 时才会赋值

参考

memory-efficient-java

深入理解Java的对象头mark word

Java对象头详解

java校招面试

Java对象结构与锁实现原理及MarkWord详解

干掉面试官1-synchronized底层原理(从Java对象头说到即时编译优化)

探究java对象头——大端存储与小端存储

JAVA对象头详解(含32位虚拟机与64位虚拟机)的更多相关文章

  1. Java对象初始化详解

    在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Java如何执行对象的初始化做一个详细深入地介绍(与对象初始化相同,类在被加载之后也是需要初始化的,本 ...

  2. Java对象初始化详解(转)

    在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Java如何执行对象的初始化做一个详细深入地介绍(与对象初始化相同,类在被加载之后也是需要初始化的,本 ...

  3. 2018.6.15 Java对象序列化详解

    一.定义 Serializable 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. ObjectOutputStream对象输出流 可以将实现了Seria ...

  4. Java对象序列化详解

    深入理解Java对象序列化 1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 ...

  5. 【转】Java对象初始化详解

    来源:MySun 链接:http://mysun.iteye.com/blog/1596959 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Jav ...

  6. Java对象克隆详解

    原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...

  7. Java 对象排序详解

    很难想象有Java开发人员不曾使用过Collection框架.在Collection框架中,主要使用的类是来自List接口中的ArrayList,以及来自Set接口的HashSet.TreeSet,我 ...

  8. 转:Java HashMap实现详解

    Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1.    HashMap概述:    HashMap是基于哈希表的M ...

  9. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

随机推荐

  1. 常用API【2】

    常用API 1.Math类 1.1 Math类概述 Math包含执行基本数字运算的方法 没有构造方法,如何使用类中的成员呢? 看类的成员是否是静态的,如果是,可以通过类名直接调用 1.2Math类的常 ...

  2. ZT:通过Find命令找到你要找的东西

    https://os.51cto.com/art/202003/612049.htm find 命令有巨多的选项可以帮助你准确定位你在 Linux 系统上需要寻找的文件.这篇文章讨论了一系列非常有用的 ...

  3. pytest132个命令行参数用法

    在Shell执行pytest -h可以看到pytest的命令行参数有这10大类,共132个 序号 类别 中文名 包含命令行参数数量 1 positional arguments 形参 1 2 gene ...

  4. Windows+Git+TortoiseGit+COPSSH安装图文教程

    http://blog.csdn.net/aaron_luchen/article/details/10498181/ http://jingyan.baidu.com/article/3a2f7c2 ...

  5. Java 9天入门(黑马程序员) 课程收尾 ------学生管理系统 (9.13)

    1 实现功能 2 结构概述 分为两个包,各自一个类 Student.java 为学生类,目的是储存学生信息 StudentManager.java 是主程序的代码 3 Student.java 的代码 ...

  6. Hadoop入门学习整理(三)

    1.Hive 的安装 下载tar包,并且要注意和Hadoop版本兼容. 下载  ----->  传输 -------> 解压     即可. 然后配置环境变量和相关配置信息.   参考: ...

  7. 【Flutter 实战】路由堆栈详解

    老孟导读:Flutter中路由是非常重要的部分,任何一个应用程序都离不开路由管理,此文讲解路由相关方法的使用和路由堆栈的变化. Flutter 路由管理中有两个非常重要的概念: Route:路由是应用 ...

  8. Scala的递归函数应用

    使用递归函数实现累加: def sum(nums:Int*):Int={ if(nums.length == 0) 0 else nums.head + sum(nums.tail:_*) } 结果为 ...

  9. react项目结合echarts,百度地图实现热力图

    一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...

  10. Servlet中关于中文乱码

    一.客户端请求服务器的数据有乱码 1.get方式请求 ①修改tomcat/conf/server.xml,在<Connector> 标签中添加属性useBodyEncodingForURI ...