一.对象的内存布局
在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
1、对象头
HotSpot虚拟机对象的对象头部分包括两类信息。第一类是用于存储对象自身的运行时数据,如哈希(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32个比特和64个比特,官方称它 为“Mark Word”。对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针。此外,如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。
2、实例数据
是对象真正存储的有效信息。
3、对齐填充 (64位机)
由于HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。
对象大小(64位机)
普通对象
1、对象头:
markword: 8个字节
ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节
2、实例数据
引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节
3、Padding对齐,8的倍数
数组对象
1、 对象头:markword 8
2、 ClassPointer指针同上
3、 数组长度:4字节
4、 数组数据
5、 对齐 8的倍数
二.使用JavaAgent测试Object的大小
1、观察虚拟机配置
java -XX:+PrintCommandLineFlags -version
zhangtianci@zhangtinsidembp ~ % java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=536870912 -XX:MaxHeapSize=8589934592 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_251"
Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.251-b08, mixed mode)
2、新建项目ObjectSize (1.8)
package com.zhangtianci.jvm.agent;
import java.lang.instrument.Instrumentation;
public class ObjectSizeAgent {
private static Instrumentation inst;
public static void premain(String agentArgs, Instrumentation _inst) {
inst = _inst;
}
public static long sizeOf(Object o) {
return inst.getObjectSize(o);
}
}
1、 src目录下创建META-INF/MANIFEST.MF
Premain-Class: com.zhangtianci.jvm.agent.ObjectSizeAgent
2、 打包jar文件
3、 在需要使用该Agent Jar的项目中引入该Jar包
project structure – project settings – library 添加该jar包
4、 运行时需要该Agent Jar的类,加入参数:
-javaagent:\xxx\ObjectSize.jar
5、 如何使用该类:
public class SizeOfAnObjectTest {
public static void main(String[] args) {
System.out.println(ObjectSizeAgent.sizeOf(new Object()));
System.out.println(ObjectSizeAgent.sizeOf(new int[] {}));
System.out.println(ObjectSizeAgent.sizeOf(new P()));
}
private static class P {
//8 _markword
//4 _oop指针
int id; //4
String name; //4
int age; //4
byte b1; //1
byte b2; //1
Object o; //4
byte b3; //1
}
}
Hotspot开启内存压缩的规则(64位机)
1、 4G以下,直接砍掉高32位
2、 4G – 32G,默认开启内存压缩 ClassPointers Oops
3、 32G,压缩无效,使用64位
内存并不是越大越好(-)
三.对象定位
在创建对象之后,可通过栈上的reference数据操作堆上的具体对象。这个reference有两种比较主流
的实现方式。
1、句柄:这种方式Java堆需要分配一块内存作为句柄池,reference存的就是句柄地址。句柄包含了对
象实例数据地址和对象类型数据地址。
2、直接指针:这种方式reference存的直接是对象地址,如果是访问对象本身则比句柄少了一次访问开
销。
hotspot 采用直接指针的方式。