Java对象内存布局和对象头
# Java 对象内存布局和对象头
# 对象在堆内存中布局
Object object = new Object() 谈谈你对这句话的理解?
一般而言 JDK8 按照默认情况下,new 一个对象占多少内存空间
- 位置所在:JVM 里堆→新生区→伊甸园区
- 构成布局:头体?想想我们的 HTML 报文
在 HotSpot 虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头 (Header)、实例数据 (Instance Data) 和对齐填充 (Padding)。

# 对象在堆内存中的存储布局
对象内部结构分为:对象头、实例数据、对齐填充(保证 8 个字节的倍数)。 对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址。

# 对象头
# 对象标记 Mark Word

它保存什么?

在 64 位系统中,Mark Word 占了 8 个字节,类型指针占了 8 个字节,一共是 16 个字节

# 类元信息 (又叫类型指针)
对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

对象头多大?
在 64 位系统中,Mark Word 占了 8 个字节,类型指针占了 8 个字节,一共是 16 个字节。
# 实例数据
存放类的属性 (Field) 数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按 4 字节对齐。
# 对齐填充
虚拟机要求对象起始地址必须是 8 字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按 8 字节补充对齐。
# 源码
http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/89fb452b3688/src/share/vm/oops/oop.hpp

_mark 字段是 mark word,_metadata 是类指针 klass pointer,对象头(object header)即是由这两个字段组成,这些术语可以参考 Hotspot 术语表

# 对象头的 MarkWord
32 位

64 位

下面以 64 位为例子进行说明


oop.hpp

markOop.hpp

- hash: 保存对象的哈希码
- age: 保存对象的分代年龄
- biased_lock: 偏向锁标识位
- lock: 锁状态标识位
- JavaThread* :保存持有偏向锁的线程 ID
- epoch: 保存偏向时间戳
markword (64 位) 分布图,对象布局、GC 回收和后面的锁升级就是对象标记 MarkWord 里面标志位的变化

# Object obj = new Object()
JOL 官网 http://openjdk.java.net/projects/code-tools/jol/
<!--
官网:http://openjdk.java.net/projects/code-tools/jol/
定位:分析对象在JVM的大小和分布
-->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
2
3
4
5
6
7
8
9
10
案例测试
package com.atguigu.juc.senior.inner.object;
import org.openjdk.jol.vm.VM;
/**
* @auther zzyy
* @create 2020-06-13 11:24
*/
public class MyObject
{
public static void main(String[] args){
//VM的细节详细情况
System.out.println(VM.current().details());
//所有的对象分配的字节都是8的整数倍。
System.out.println(VM.current().objectAlignment());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

使用 jol 分析对象在 JVM 的大小和分布
package com.atguigu.juc.prepare;
import org.openjdk.jol.info.ClassLayout;
/**
* @auther zzyy
* @create 2020-04-12 15:11
*/
public class JOLDemo
{
public static void main(String[] args)
{
Object o = new Object();
System.out.println( ClassLayout.parseInstance(o).toPrintable());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

- OFFSET:偏移量,也就是到这个字段位置所占用的 byte 数
- SIZE:后面类型的字节大小
- TYPE:是 Class 中定义的类型
- DESCRIPTION:DESCRIPTION 是类型的描述
- VALUE:VALUE 是 TYPE 在内存中的值
# GC 年龄
GC 年龄采用 4 位 bit 存储,最大为 15,例如 MaxTenuringThreshold 参数默认值就是 15
-XX:MaxTenuringThreshold=16

# 尾巴参数说明
java -XX:+PrintCommandLineFlags -version
-XX:+UseCompressedClassPointers:默认开启压缩说明

上述表示开启了类型指针的压缩,以节约空间,假如不加压缩???我们手动关闭压缩试试看。
-XX:-UseCompressedClassPointers

# 换成其他对象试试

