IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JAVA 对象内存布局 -> 正文阅读

[Java知识库]JAVA 对象内存布局

引言

在 HotSpot 虚拟机中,创建一个对象后,该对象在堆内存中的存储布局划分为三个部分:对象头、实例数据和对齐补充。
本篇文章主要以创建对象后,对象在堆内存中的存储布局为主,想要了解创建对象的过程可以先去看这篇文章 从 JVM 虚拟机角度去看一个对象的创建过程
另外还需要补充的是,如果本篇文章中有讲的不对的地方,可以直接私我或在下方评论,感谢!


一、对象头(Header)

当我们创建对象后,虚拟机堆中对象的对象头中包括了两类信息:


第一类:运行时数据

第一类是用于存储自身的运行时数据,比如说,哈希码( HashCode )、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等,这部分的数据长度在 32 位和 64 位的虚拟机中(未开启 压缩指针)分别占用 32 个比特和 64 个比特,官方称它为 “Mark Work”

压缩指针

刚刚上面提到了压缩指针,在这里我简单讲一下压缩指针:
在堆中,32 位的对象引用指针占 4 个字节,而 64 位的对象引用占 8 个字节。也就是说,64 位的对象引用大小是 32 位的 2 倍。64 位 JVM 在支持更大堆的同时,由于对象引用变大却带来了性能问题;
第一:64 位对象引用需要占用更多的堆空间,留给其他数据的空间将会减少,从而更加频繁的进行 GC,所以增加了 GC 开销。
第二:64 位对象引用增大了,CPU 能缓存的 OOP(普通对象指针) 将会更少,从而降低了 CPU 缓存的效率,所以降低 CPU 缓存命中率。
为了能够保持 32 位的性能,OOP(普通对象指针)必须保留 32 位,所以才要使用了 压缩指针 技术来保留 32 位;


接下来继续讲对象头:
其实一个对象需要存储的运行时数据很多,已经超出了 32、64 位 Bitmap 结构所能记录的最大限度,但对象头里的信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word 被设计成一个有着动态定义的数据结构,方便在极小的空间内存储尽量多的数据,根据对象的状态复用自己的存储空间。

比如说在 32 位的 HotSpot 虚拟机中,如果对象未被同步锁锁定的状态下,Mark Word 的 32 个比特存储空间中的 25 个比特用于存储对象哈希码,4 个比特用于存储对象分代年龄,2 个比特用于存储锁标志位,1 个比特固定为 0,在其他状态(轻量级锁定、重量级锁定、GC 标记、偏向锁定)下,这 1 个比特则变成 1。

在这里插入图片描述


第二类:类型指针

对象头的另外一部分是类型指针,就是对象指向它的类型元数据的指针,JAVA 虚拟机通过这个指针来确定该对象是哪个类的实例。
但是并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息并不一定要经过对象本身。

此外,如果对象是一个 JAVA 数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通 JAVA 对象的元数据信息确定 JAVA 对象的大小,但是如果数组的长度是不确定的,将无法通过元数据中的信息推断出数组的大小。


二、实例数据

实例数据部分是对象真正存储的有效信息,就是我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。
这部分的存储顺序会受到 虚拟机分配策略参数(参数:-XX:FieldsAllocationStyle) 和字段在 JAVA 源码中定义顺序的影响。

内存分配策略

这里简单的扩充一下虚拟机内存分配策略,当我们创建对象时,大多数情况下,新创建的对象都会在堆内存中的新生代 Eden 区进行分配内存。
Eden 区没有足够的空间进行分配时,虚拟机会发起一次 Minor GC,如果本次 Minor GC 后还是没有足够的空间,则将启用分配担保机制在老年代中分配内存。

接下来继续讲实例数据:
HotSpot虚拟机默认的分配顺序为:longs / doubles、ints、shorts / chars、bytes / booleans、oops(Ordinary Object Pointers,OOPs)(普通对象指针)
从以上默认的分配策略中可以看到,相同宽度的字段总是被分配到一起存放,在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。
如果HotSpot虚拟机的 +XX:CompactFields 参数值为true(默认就是 true),那子类之中较窄的变量也允许插入父类变量的空 隙之中,以节省出一点点空间。


三、对齐补充

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



本篇文章主要来源于《深入理解JAVA虚拟机》


End


  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:22:10  更:2021-08-01 14:23:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 10:38:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码