【HotSpot】一个java对象占多少空间
作者:threedayman以下内容基于HotSpot虚拟机进行讲解验证。
来源:恒生LIGHT云社区
理论知识 对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头中有两类信息
- 运行时数据:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
- 类型指针:对象指向它类型元数据的指针,虚拟机通过这个指针来确定该对象是哪个类的实例。
- 对象存储的有效信息,即我们在程序代码中定义的各种类型的字段内容。
- HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,如果对象占用空间不是8个字节的整数倍,就需要通过对齐填充来补全。
实践检验 通过Instrumentation的getObjectSize方法去测量对象占用大小。具体代码如下
package org.example;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
public class SizeOfObject {
static Instrumentation inst;
public static void premain(String args, Instrumentation instP) {
inst = instP;
}/**
* 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小
*
* @param obj
* @return
*/
public static long sizeOf(Object obj) {
return inst.getObjectSize(obj);
}/**
* 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
*
* @param objP
* @return
* @throws IllegalAccessException
*/
public static long fullSizeOf(Object objP) throws IllegalAccessException {
Set
测试对象大小代码
package org.example;
import static org.example.SizeOfObject.fullSizeOf;
import static org.example.SizeOfObject.sizeOf;
public class SizeOfObjectTest {/**
*-XX:+UseCompressedOops: Header 12Padding 4= 16
*-XX:-UseCompressedOops: Header 16 = 24
*/
static class A1 {
}
/**
* -XX:+UseCompressedOops: Header 12 + Instance Data 4 = 16
* -XX:-UseCompressedOops: Header 16 + Instance Data 4 + Padding 4 = 24
*/
static class A {
int a;
}/**
* -XX:+UseCompressedOops: Header 12 + Instance Data 4 + 4 + padding 4 = 24
* -XX:-UseCompressedOops: Header 16 + Instance Data 4 + 4 = 24
*/
static class B {
int a;
int b;
}/**
* -XX:+UseCompressedOops: Header 12 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops:Header 16 + 8 + 4 + padding/4 = 32
*/
static class B2 {
int b2a;
Integer b2b;
}/**
* 不考虑对象头:
* 4 + 4 + 4 * 3 + 3 * sizeOf(B)
*/
static class C extends A {
int ba;
B[] as = new B[3];
C() {
for (int i = 0;
i < as.length;
i++) {
as[i] = new B();
}
}
}static class D extends B {
int da;
Integer[] di = new Integer[3];
}/**
* 会算上A的实例字段
*/
static class E extends A {
int ea;
int eb;
}public static void main(String[] args) throws IllegalAccessException {
System.out.println("sizeOf(new A1())=" + sizeOf(new A1()));
System.out.println("sizeOf(new A())=" + sizeOf(new A()));
System.out.println("sizeOf(new B())=" + sizeOf(new B()));
System.out.println("sizeOf(new B2())=" + sizeOf(new B2()));
System.out.println("sizeOf(new B[3])=" + sizeOf(new B[3]));
System.out.println("sizeOf(new C())=" + sizeOf(new C()));
System.out.println("fullSizeOf(new C())=" + fullSizeOf(new C()));
System.out.println("sizeOf(new D())=" + sizeOf(new D()));
System.out.println("fullSizeOf(new D())=" + fullSizeOf(new D()));
System.out.println("sizeOf(new int[3])=" + sizeOf(new int[3]));
System.out.println("sizeOf(new Integer(1)=" + sizeOf(new Integer(1)));
System.out.println("sizeOf(new Integer[0])=" + sizeOf(new Integer[0]));
System.out.println("sizeOf(new Integer[1])=" + sizeOf(new Integer[1]));
System.out.println("sizeOf(new Integer[2])=" + sizeOf(new Integer[2]));
System.out.println("sizeOf(new Integer[3])=" + sizeOf(new Integer[3]));
System.out.println("sizeOf(new Integer[4])=" + sizeOf(new Integer[4]));
System.out.println("sizeOf(new A[3])=" + sizeOf(new A[3]));
System.out.println("sizeOf(new E())=" + sizeOf(new E()));
}
}
打包插件中增加以下配置
maven-jar-plugin
3.0.2
test
org.example.SizeOfObject
false
org.example.SizeOfObjectTest
false
配置指定的main方法入口类、agent增强类入口。默认情况下 开启了指针压缩。
D:\ideaproject\size-agent\target>java -javaagent:test.jar -jar test.jar
sizeOf(new A1())=16
sizeOf(new A())=16
sizeOf(new B())=24
sizeOf(new B2())=24
sizeOf(new B[3])=32
sizeOf(new C())=24
fullSizeOf(new C())=128
sizeOf(new D())=32
fullSizeOf(new D())=64
sizeOf(new int[3])=32
sizeOf(new Integer(1)=16
sizeOf(new Integer[0])=16
sizeOf(new Integer[1])=24
sizeOf(new Integer[2])=24
sizeOf(new Integer[3])=32
sizeOf(new Integer[4])=32
sizeOf(new A[3])=32
sizeOf(new E())=24
关闭指针压缩
D:\ideaproject\size-agent\target>java -javaagent:test.jar -XX:-UseCompressedOops -jar test.jar
sizeOf(new A1())=16
sizeOf(new A())=24
sizeOf(new B())=24
sizeOf(new B2())=32
sizeOf(new B[3])=48
sizeOf(new C())=40
fullSizeOf(new C())=160
sizeOf(new D())=40
fullSizeOf(new D())=88
sizeOf(new int[3])=40
sizeOf(new Integer(1)=24
sizeOf(new Integer[0])=24
sizeOf(new Integer[1])=32
sizeOf(new Integer[2])=40
sizeOf(new Integer[3])=48
sizeOf(new Integer[4])=56
sizeOf(new A[3])=48
sizeOf(new E())=32
大家还可以根据自己想要了解的情况去更改上述代码,用来验证自己的理论知识是否正确。
参考
《深入理解java虚拟机》
【【HotSpot】一个java对象占多少空间】https://www.iteye.com/blog/yueyemaitian-2033046
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长