对于 Java 虚拟机,我们都知道其内存区域划分成:堆、方法区、虚拟机栈等区域。但一个对象在 Java 虚拟机中是怎样存储的,相信很少人会比较清楚地了解。Java 对象在 JVM 中的内存布局,是我们了解并发编程同步机制的基础。

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

对象头

HotSpot 虚拟机的对象头包括两部分信息,第一部分用于存储自身运行时的数据,第二部分用于存储类型指针。

自身运行时数据

对象头第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。这部分数据的长度在 32 位和 64 位的虚拟机中分别为 32bit 和 64bit,官方称它为「Mark Word」。

为了提高虚拟机的空间效率,Mark Word 被设计成非固定的数据结构,从而可以在不同状态时存储不同的数据,从而达到节省数据空间的目的。Mark Word 在不同状态下存储的内容如下表格所示。

如上表所示,在 32 位的 HotSpot 虚拟机中,如果对象处于未被锁定(标志位为 01)的状态下,那么 Mark Word 存储的就是「对象哈希码、对象分代年龄」。32bit 空间中的 25bit 用于存储对象哈希码,4bit 用于存储对象分代年龄,2bit 用于存储锁标志位,1bit 固定为 0。

类型指针

对象头第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。 另外,如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通 Java 对象的元数据信息确定 Java 对象的大小,但是从数组的元数据中却无法确定数组的大小。

实例数据

实例数据部分是对象真正存储的有效信息,包括了程序里各个类型的字段类型,无论是父类继承下来的,还是子类中定义的。一般来说,父类定义的变量总会出现在子类之前。

对齐填充

对象填充部分并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于 HotSpot VM 的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

总结

本篇文章我们介绍了 Java 对象在 JVM 中的内存布局,整体可以分为:对象头、实例数据、对齐填充三个部分。

第一部分的对象头包括了对象运行时数据和类型指针。其中对象运行时数据包括:哈希码、GC 分代年龄、锁状态标志等,类型指针指向对象类型元数据,确定对象是哪个类的实例。第二部分是实例数据,是真正存储的有效信息,包括各个类型的字段。第三部分是对齐填充,因为 JVM 要求对象起始地址必须是 8 字节的整数倍,所以必须有对齐填充来占位。

深入理解 Java 对象的内存布局的更多相关文章

  1. Java对象的内存布局

    对象的内存布局 平时用java编写程序,你了解java对象的内存布局么? 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域: 对象头 实例数据 对齐填充 对象头 对象头包括两部分信息: ...

  2. Java对象的内存布局以及对象的访问定位

    一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储 ...

  3. 3 Java对象的内存布局以及对象的访问定位

    先来看看Java对象在内存中的布局   一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机 ...

  4. Java对象的内存布局以及对象所需内存大小计算详解

    1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...

  5. Linux Debugging(四): 使用GDB来理解C++ 对象的内存布局(多重继承,虚继承)

    前一段时间再次拜读<Inside the C++ Object Model> 深入探索C++对象模型,有了进一步的理解,因此我也写了四篇博文算是读书笔记: Program Transfor ...

  6. JVM总结-java对象的内存布局

    在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的 new 语句之外,我们还可以通过反射机制.Object.clone 方法.反序列化以及 Unsafe.allocateInstance ...

  7. 10 Java 对象的内存布局

    Java 创建对象的方式 1:new 语句和反射机制创建.该方式会调用类的构造器,同时满足诸多约束.如果一个类没有构造器的话,Java 编译器会自动添加一个无参数的构造器.子类的构造器需要调用父类的构 ...

  8. 一个Java对象的内存布局

    1.对象的创建过程 class loading class linking(verification,preparation,resolution) class initializing 申请对象内存 ...

  9. java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

    在上一篇文章中.我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下.如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证 ...

随机推荐

  1. 通过 SingleFlight 模式学习 Go 并发编程

    最近接触到微服务框架go-zero,翻看了整个框架代码,发现结构清晰.代码简洁,所以决定阅读源码学习下,本次阅读的源码位于core/syncx/singleflight.go. 在go-zero中Si ...

  2. 机器学习-学习笔记(一) --> (假设空间 & 版本空间)及 归纳偏好

    机器学习 一.机器学习概念 啥是机器学习 机器学习:假设用P来评估计算机程序在某任务类T上的性能,若一个程序通过利用经验E在T中任务上获得了性能改善,则关于T和P,该程序对E进行了学习 通俗讲:通过计 ...

  3. 原来 Linux 日志文件系统是这样工作的~

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 作者:Linux Performance 链接:http://linuxperf.com/?p ...

  4. 记将一个大型客户端应用项目迁移到 dotnet 6 的经验和决策

    在经过了两年的准备,以及迁移了几个应用项目积累了让我有信心的经验之后,我最近在开始将团队里面最大的一个项目,从 .NET Framework 4.5 迁移到 .NET 6 上.这是一个从 2016 时 ...

  5. Dns2tcp隧道

    0x01 dns2tcp绕过的原理 dns2tcp是一款基于c/s架构的软件,它可以将通信报文夹藏在udp协议的TXT解析记录中,进而形成dns隧道.dns隧道通过dns2tcpc对本地端口的监听,实 ...

  6. C#/VB.NET 创建图片超链接

    超链接(Hyperlink)可以看做是一个"热点",它可以从当前Web页定义的位置跳转到其他位置,包括当前页的某个位置.Internet.本地硬盘或局域网上的其他文件,甚至跳转到声 ...

  7. 【Java分享客栈】未来迈向高级工程师绕不过的技能:JMeter压测

    前言 因为工作需要,久违的从自己的有道云笔记中去寻找压测相关的内容,翻开之后发现还不错,温故一遍后顺便整理出来分享给大家. 题外话,工作8年多,有道云笔记不知不觉都6G多了,扫一眼下来尽是云烟过往,竟 ...

  8. mapstruct 的 mapstruct-processor 自动生成的 Impl 文件中未设置属性值(时好时坏)

    配置依赖和注解处理器 ... <properties> <org.mapstruct.version>1.4.2.Final</org.mapstruct.version ...

  9. 好客租房16-jsx中的列表渲染

    如果要渲染一组数组 应该使用数组的map方法 注意:渲染列表时候添加key属性 key属性的值要保持唯一 原则:map()遍历谁 就给谁添加key属性 尽量避免索引号作为key //导入react i ...

  10. 声学感知刻度(mel scale、Bark scale、ERB)与声学特征提取(MFCC、BFCC、GFCC)

    梅尔刻度 梅尔刻度(Mel scale)是一种由听众判断不同频率 音高(pitch)彼此相等的感知刻度,表示人耳对等距音高(pitch)变化的感知.mel 刻度和正常频率(Hz)之间的参考点是将1 k ...