11.Java对象内存布局和对象头
本笔记来源于:尚硅谷JUC并发编程(对标阿里P6-P7)
b站视频文章来自:
https://www.yuque.com/gongxi-wssld/csm31d/ln0mq1w7wp1oy99g
https://www.yuque.com/liuyanntes/vx9leh/fpy93i
https://blog.csdn.net/dolpin_ink/category_11847910.html
脑图
本地:
尚硅谷JUC并发编程
在线:
尚硅谷JUC并发编程
在线脑图加载时间超长。
1、先从阿里及其他大厂面试题说起
2、Object object = new Object()
谈谈你对这句话的理解?一般而言JDK8按照默认情况下,new一个对象占多少内存空间
2.1 位置所在
在JVM堆里的新生区的伊甸园区(这些都是之前的基础知识了)
2.2 构成布局
可以联想一下我们的HTML报文
3、对象在堆内存中布局
3.1 权威定义—周志明老师JVM第3版
在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:
对象头
实例数据
对齐填充
3.2 对象在堆内存中的存储布局
下面分别是 java对象 和数组(数组对象会多一个length),原理其实类似
3.2.1.对象头
- 对象头分为对象标记(markOpp)和 类元信息 (klassOop)
- 类元信息存储的是指向该对象类元数据(klass)的首地址。
先提出几个问题来引出下面的概念
1 |
|
先回复一下问题
- 刚刚几个问题都保存在对象标记里
对象标记Mark Word
- 在64位系统中,MarkWord占了8个字节,类型指针占了8个字节,一共是16个字节
默认存储对象的HashCode、分代年龄和锁标志位等信息。这些信息都是与对象自身定于无关的数据,所以MarkWord被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据。它会根据对象的状态复用自己的存储空间,也就是说在运行期间MarkWord上存储的数据会随着锁标志位的变化而变化。
类元信息(又叫类型指针)Class Pointer
所谓的类元信息(类型指针)其实就可以说是模板
- 尚硅谷宋红康老师的图
- 对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的示例。
对象头多大
对象头有多大?
- 在64位系统中,MarkWord占了8个字节,类型指针占了8个字节,一共是16个字节
3.2.2.实例数据
实例数据:存放类的属性(Field)信息,包括父类的属性信息
3.2.3.对齐填充
用来保证8字节的倍数
对齐填充:虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按8字节补充对齐。
有个案例,对象头16+实例数据5+对齐填充3=24字节
3.3 官网理论
mark字段是mark word,metadata是类指针klass pointer,
对象头(object header)即是由这两个字段组成,这些术语可以参考Hotspot术语表,
4、再说对象头的MarkWord
32位(看一下即可,不用学了,以64位为准)
64位重要
- 看看C中的源码
- oop.hpp
- markOop.hpp
hash:保存对象的哈希码
age: 保存对象的分代年龄
biased_lock: 偏向锁标识位
lock: 锁状态标识位
JavaThread :保存持有偏向锁的线程ID
epoch: 保存偏向时间戳
markword(64位)分布图
对象布局、GC回收和后面的锁升级就是对象标记MarkWord里面标志位的变化
5、聊聊Object obj = new Object()【用代码演示】
5.1 JOL证明
JOL工具(Java Object Layout工具)-可以帮助分析对象在Java虚拟机中的大小和布局
http://openjdk.java.net/projects/code-tools/joll (网站已经失效了)
但我们可以直接用依赖来实现这个功能
1 |
|
1 |
|
5.2 代码
演示一、用自带的类
1 |
|
这里丢下一个疑问,为什么类型指针是4字节?之前不都是说是8字节的吗?(因为压缩指针默认开启了,后面有讲)
演示二、用自己的类
1 |
|
1 |
|
5.3 GC年龄采用4位bit存储,最大位15,例如MaxTenuringThreshold参数默认值就是15
- 对象分代年龄最大就是15
如果想证明一下
- 我们假如想直接把分代最大年龄修改为16会直接报错。
-XX:MaxTenurningThreshold=16
5.4 尾巴参数说明(压缩指针相关)
压缩指针相关的命令(压缩指针是否开启对我们new一个对象是不是16字节的影响)
查看当前JVM运行参数的指令
java -XX:+PrintCommandLineFlags -version
压缩指针默认是开启的
(这也就解释了为什么前面的类型指针是4个字节,节约了内存空间)
假如不压缩的情况?我们手动关闭压缩指针看看?
+是开启,-就是关闭,所以指令是-XX:-UseCompressedClassPointers
也要注意,不管是否开启压缩指针,创建一个对象就是16字节的。(开启压缩指针后缺失的会由对齐填充补充)
6、换成其他对象试试
- 同样的道理