Java对象的内存布局

Mark Word

用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等。

Mark Word在32位JVM中的长度是32bit,在64位JVM中长度是64bit。我们打开openjdk的源码包,对应路径 /openjdk/hotspot/src/share/vm/oops,Mark Word对应到C++的代码 markOop.hpp,可以从注释中看到它们的组成,本文所有代码是基于Jdk1.8。

Java对象的内存布局

Mark Word在不同的锁状态下存储的内容不同,在32位JVM中是这么存的

Java对象的内存布局

在64位JVM中是这么存的

Java对象的内存布局

虽然它们在不同位数的JVM中长度不一样,但是基本组成内容是一致的。

  • 锁标志位(lock):区分锁状态,11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。
  • biased_lock:是否偏向锁,由于正常锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。
  • 分代年龄(age):表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
  • 对象的hashcode(hash):运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。当对象加锁后,计算的结果31位不够表示,在偏向锁,轻量锁,重量锁,hashcode会被转移到Monitor中。
  • 偏向锁的线程ID(JavaThread):偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。
  • epoch:偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。
  • ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。当锁获取是无竞争的时,JVM使用原子操作而不是OS互斥。这种技术称为轻量级锁定。在轻量级锁定的情况下,JVM通过CAS操作在对象的标题字中设置指向锁记录的指针。
  • ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针。如果两个不同的线程同时在同一个对象上竞争,则必须将轻量级锁定升级到Monitor以管理等待的线程。在重量级锁定的情况下,JVM在对象的ptr_to_heavyweight_monitor设置指向Monitor的指针。

Klass Pointer

即类型指针,是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

实例数据

如果对象有属性字段,则这里会有数据信息。如果对象无属性字段,则这里就不会有数据。根据字段类型的不同占不同的字节,例如boolean类型占1个字节,int类型占4个字节等等;

对齐数据

对象可以有对齐数据也可以没有。默认情况下,Java虚拟机堆中对象的起始地址需要对齐至8的倍数。如果一个对象用不到8N个字节则需要对其填充,以此来补齐对象头和实例数据占用内存之后剩余的空间大小。如果对象头和实例数据已经占满了JVM所分配的内存空间,那么就不用再进行对齐填充了。

所有的对象分配的字节总SIZE需要是8的倍数,如果前面的对象头和实例数据占用的总SIZE不满足要求,则通过对齐数据来填满。

为什么要对齐数据?字段内存对齐的其中一个原因,是让字段只出现在同一CPU的缓存行中。如果字段不是对齐的,那么就有可能出现跨缓存行的字段。也就是说,该字段的读取可能需要替换两个缓存行,而该字段的存储也会同时污染两个缓存行。这两种情况对程序的执行效率而言都是不利的。其实对其填充的最终目的是为了计算机高效寻址。

至此,我们已经了解了对象在堆内存中的整体结构布局,如下图所示

Java对象的内存布局

openjdk 给我们提供了一个工具包,可以用来获取对象的信息和虚拟机的信息,我们只需引入 jol-core 依赖,如下

org.openjdk.jol
  jol-core
  0.8

jol-core 常用的三个方法

  • ClassLayout.parseInstance(object).toPrintable():查看对象内部信息.

  • GraphLayout.parseInstance(object).toPrintable():查看对象外部信息,包括引用的对象.

  • GraphLayout.parseInstance(object).totalSize():查看对象总大小.

普通对象

为了简单化,我们不用复杂的对象,自己创建一个类 D,先看无属性字段的时候

public class D {
}

通过 jol-core 的 api,我们将对象的内部信息打印出来

public static void main(String[] args) {
    D d = new D();
    System.out.println(ClassLayout.parseInstance(d).toPrintable());
}

最后的打印结果为

Java对象的内存布局

可以看到有 OFFSET、SIZE、TYPE DESCRIPTION、VALUE 这几个名词头,它们的含义分别是

  • OFFSET:偏移地址,单位字节;
  • SIZE:占用的内存大小,单位为字节;
  • TYPE DESCRIPTION:类型描述,其中object header为对象头;
  • VALUE:对应内存中当前存储的值,二进制32位;

Java对象的内存布局

可以看到,d对象实例共占据16byte,对象头(object header)占据12byte(96bit),其中 mark word占8byte(64bit),klass pointe 占4byte,另外剩余4byte是填充对齐的。

这里由于默认开启了 指针压缩 ,所以对象头占了12byte,具体的指针压缩的概念这里就不再阐述了,感兴趣的读者可以自己查阅下官方文档。jdk8版本是默认开启指针压缩的,可以通过配置vm参数开启关闭指针压缩, -XX:-UseCompressedOops

Java对象的内存布局

如果关闭指针压缩重新打印对象的内存布局,可以发现总SIZE变大了,从下图中可以看到,对象头所占用的内存大小变为16byte(128bit),其中 mark word占8byte,klass pointe 占8byte,无对齐填充。

Java对象的内存布局

开启指针压缩可以减少对象的内存使用。从两次打印的D对象布局信息来看,关闭指针压缩时,对象头的SIZE增加了4byte,这里由于D对象是无属性的,读者可以试试增加几个属性字段来看下,这样会明显的发现SIZE增长。因此开启指针压缩,理论上来讲,大约能节省百分之五十的内存。jdk8及以后版本已经默认开启指针压缩,无需配置。

数组对象

上面使用的是普通对象,我们来看下数组对象的内存布局,比较下有什么异同

public static void main(String[] args) {
    int[] a = {1};
    System.out.println(ClassLayout.parseInstance(a).toPrintable());
}

打印的内存布局信息,如下

Java对象的内存布局

可以看到这时总SIZE为共24byte,对象头占16byte,其中Mark Work占8byte,Klass Point 占4byte,array length 占4byte,因为里面只有一个int 类型的1,所以数组对象的实例数据占据4byte,剩余对齐填充占据4byte。

结尾

经过以上的内容我们了解了对象在内存中的布局,了解对象的内存布局和对象头的概念,特别是对象头的Mark Word的内容,在我们后续分析 synchronize 锁优化 和 JVM 垃圾回收年龄代的时候会有很大作用。

JVM中大家是否还记得对象在Suvivor中每熬过一次MinorGC,年龄就增加1,当它的年龄增加到一定程度后就会被晋升到老年代中,这个次数默认是15岁,有想过为什么是15吗?在Mark Word中可以发现标记对象分代年龄的分配的空间是4bit,而4bit能表示的最大数就是2^4-1 = 15。

Original: https://www.cnblogs.com/JonaLin/p/13864578.html
Author: 一支会记忆的笔
Title: Java对象的内存布局

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/538030/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • bsd socket 网络通讯必备工具类

    传输数据的时候都要带上包头,包头有简单的又复杂的,简单的只要能指明数据的长度就够了。 这里我写了一个工具类,可以方便地将整型的数据长度转换为长度为 4 的字节数组。 另一方面,可以…

    Java 2023年5月29日
    084
  • MongoDB高级应用之数据转存与恢复(5)

    1、MongoDB索引 1.1、创建索引 db.books.ensureIndex{{number:1}} 创建索引同时指定索引的名字 db.books.ensureIndex({…

    Java 2023年6月7日
    094
  • 输出单链表倒数第K个结点值

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月5日
    082
  • 基于ssm的宠物医院系统(附源码)

    摘要 随着国内经济的发展,GDP的提高,人们的幸福指数的不断提高,越来越多的珍稀品种的猫狗成为家庭的一部分。宠物主人非常重视宠物的治疗,于是宠物医院应运而生。一家正规的宠物医院必须…

    Java 2023年6月7日
    077
  • Mybatis 记录

    {}, ${}两种传参数方式的区别 1) ${} 会将传入的参数完全拼接到sql语句中,也就是相当于一个拼接符号。 也就是,最后的处理方式就相当于 String sql = sel…

    Java 2023年5月30日
    054
  • 前后端分离,SpringBoot如何实现验证码操作

    验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的。 SpringBoot版本 本文基于的Sp…

    Java 2023年6月8日
    087
  • Android-Java-接口Interface

    接口Interface 与 抽象类不同: 抽象类关注的是事物本质,例如:水果Fruit 属于抽象的,说去买水果 是模糊的概念 是抽象的概念 不具体,到底买什么水果不知道,而水果包含…

    Java 2023年5月29日
    080
  • 如何使用(扫描)二维码进行登录

    一、项目背景 这是我加入博&#x5BA2…

    Java 2023年6月14日
    076
  • IaaS/ PaaS/ SaaS

    PaaS(平台即服务) 如 低代码平台IaaS (基础架构即服务) 如 阿里云主机SaaS (软件即服务) 如 淘宝之于卖家 Original: https://www.cnblo…

    Java 2023年6月15日
    073
  • Java 的强引用、弱引用、软引用、虚引用

    转载自:https://www.cnblogs.com/gudi/p/6403953.html 1、强引用(StrongReference) 强引用是使用最普遍的引用。如果一个对象…

    Java 2023年5月29日
    0102
  • nginx重新整理——————nginx 的网络模型[九]

    前言 简单介绍一下nginx的网络模型。 正文 网络拓扑图: 数据流: 网络传输大概是这样传输的。 nginx 事件循环: 事件处理过程: 上面两张图什么意思呢? 其实就是说,ng…

    Java 2023年5月30日
    072
  • 基于 openssl 及 keytool 创建 ssl 证书并配置到 nginx 和 tomcat

    1、openssl 创建 crt 证书示例 2、nginx 配置 crt 证书示例 3、keytool 创建 keystore 证书示例 如需添加 SAN 信息则 通过 -ext …

    Java 2023年5月30日
    070
  • SSM常见面试

    HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。 Han…

    Java 2023年6月9日
    094
  • 4.门面Slf4j+slf4j-log4j12+log4j

    1.导入pom依赖 org.slf4j slf4j-api 1.7.27 org.slf4j slf4j-log4j12 1.7.27 log4j log4j 1.2.17 2.增…

    Java 2023年6月13日
    068
  • java学习笔记1(入门级)

    JavaSE (Java标准版) JavaEE(Java企业版) JavaME(Java微型版) 简单性:例如C++支持多继承,多继承比较复杂,而Java不在支持多继承 C++中有…

    Java 2023年6月16日
    077
  • Quorum 机制

    分布式系统的设计中会涉及到许多的协议、机制用来解决可靠性问题、数据一致性问题等,Quorum 机制就是其中的一种。我们通过分布式系统中的读写模型来简单介绍它。 分布式系统中的读写模…

    Java 2023年6月15日
    068
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球