Java对象内存布局详解
Java实例化之后,存储在堆内存中。其中主要分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)
具体如下图
文章图片
对象组成 1 对象头
对象头主要有两部分组成:Mark Word 和 Klass word(Class Pointer) ;如果对象是数组,还需要有数组长度
1.1 Mark Word
主要用来存储对象自身运行时数据 如 hashcode,gc分代年龄 等信息,Mark位长度与系统保持一致,32位系统 则长度为32位4字节,64位系统则长度为64位8字节;
对象头格式 :
文章图片
32位格式
文章图片
64位格式 lock:2位的锁状态标记
biased_lock: 是否启用 偏向锁,1位。1启用 0不启用
文章图片
锁与偏向锁标志 age: 4位,Java对象年龄,Survivor复制一次,年龄+1;到达阈值晋升到老年代;默认情况下,并行GC阈值为15(4位最大是15),并发为6。-XX:MaxTenuringThreshold选项最大值为15,也是这个原因
thread: 持有偏向锁的线程ID
epoch: 偏向时间戳
identity_hashcode: 对象标识hash码,由System.identityHashCode()计算。对象被锁定时,转移到管程Monitor中
ptr_to_lock_record: 指向栈中锁记录的指针
ptr_to_heavyweight_monitor: 指向管程Monitor的指针
具体存储内容如下
32位JVM
文章图片
32位JVM 64位JVM
文章图片
64位JVM存储 1.2 Klass Word(Class Poinnter)
klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.
如果应用对象过多时,使用64位指针比32位指针消耗更多内存,可以使用 +UseCompressedOops
开启指针压缩 节约内存;其中,oop即ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:每个Class的属性指针(即静态变量)、每个对象的属性指针(即对象变量)、普通对象数组的每个元素指针
当然,也不是所有的指针都会压缩,一些特殊类型的指针JVM不会优化,比如指向PermGen的Class对象指针(JDK8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。
1.3 对象头大小计算
1. 在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。
2. 在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。
3. 64位开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。 数组长度4字节+数组对象头8字节(对象引用4字节(未开启指针压缩的64位为8字节)+数组markword为4字节(64位未开启指针压缩的为8字节))+对齐4=16字节。
4. 静态属性所占用的空间通常不算在对象本身,因为它的引用是在方法区。
2 实例数据
对象真正存储的有效信息,各类型字段的内容
3 对齐填充
JVM要求 java对象占用内存必须是8 字节的倍数。如果整体占用不足8字节的倍数,则填充对应数量的占位符达到8字节倍数。
参考:
java对象头实现
JAVA 对象头解析
Java对象结构及大小计算
【Java对象内存布局详解】Java对象结构与锁实现原理及MarkWord详解
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- Java|Java基础——数组
- RxJava|RxJava 在Android项目中的使用(一)
- java之static、static|java之static、static final、final的区别与应用
- jQuery插件