9大内存对象 java_java 对象内存大小

java 一个对象内存有多大

为什么想知道这个,自以为很重要,其实 just for fun =。=

测试相关说明

jdk: java 官网上下载的,HotSpot 虚拟机

java version "1.8.0_121"

Java(TM) SE Runtime Environment (build 1.8.0_121-b13)

Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

使用的方法: Instrumentation 参考的是 一个对象占用多少字节?

确认编译时是 32 位还是 64 位,对测试结果有影响。x86 为 32 位, amd64 为 64 位,其余我不知道

System.out.println(System.getProperty("os.arch"));

准备工作

SizeOfObject.java 直接从上面链接上拷贝

编译这个类,得到 .class 文件

在包名路径下执行一下命令进行打包(注意修改相应的包名):

jar cvfm SizeOfObject.jar manifest.mf org/seal_de/SizeOfObject.class

其中 manifest.mf 清单信息为: PreMain-Class: org.seal_de.SizeOfObject

PS: 如果在打包好的 jar 包中,META-INF/MANIFEST.MF 没有 PreMain-Class 属性,添加上去即可

在运行测试程序的时候,添加 vm 参数

-javaagent:{jar包路径}\SizeOfObject.jar

测试用例

测试 int, Object, 引用的大小。其余类型测试都类似

public class MemoryTest {

/**

* -javaagent:{jar包路径}\SizeOfObject.jar -XX:+UseCompressedOops

* 使用指针压缩,在一定情况下64位HotSpot jvm默认指针压缩

*

*Output:

*amd64

*Object: 16

*

*include one int: 16

*include two int: 24

*include three int: 24

*

*include one object: 16

*include one object: 24

*/

static void test1() {

System.out.println(System.getProperty("os.arch"));

System.out.printf("%-30s%9d\n", "Object:", SizeOfObject.sizeOf(new Object()));

System.out.println();

System.out.printf("%-30s%9d\n", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne()));

System.out.printf("%-30s%9d\n", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo()));

System.out.printf("%-30s%9d\n", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree()));

System.out.println();

System.out.printf("%-30s%9d\n", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne()));

System.out.printf("%-30s%9d\n", "include one object:", SizeOfObject.sizeOf(new ReferenceTestTwo()));

}

/**

* -javaagent:{jar包路径}\SizeOfObject.jar -XX:-UseCompressedOops

* 不使用指针压缩

*

*Output:

*amd64

*Object: 16

*

*include one int: 24

*include two int: 24

*include three int: 32

*

*include one object: 24

*include one object: 32

*/

static void test2() {

System.out.println(System.getProperty("os.arch"));

System.out.printf("%-30s%9d\n", "Object:", SizeOfObject.sizeOf(new Object()));

System.out.println();

System.out.printf("%-30s%9d\n", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne()));

System.out.printf("%-30s%9d\n", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo()));

System.out.printf("%-30s%9d\n", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree()));

System.out.println();

System.out.printf("%-30s%9d\n", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne()));

System.out.printf("%-30s%9d\n", "include one object:", SizeOfObject.sizeOf(new ReferenceTestTwo()));

}

public static void main(String[] args) {

test2();

}

static class IntegerTestOne {

private int i1 = 1;

}

static class IntegerTestTwo {

private int i1 = 1;

private int i2 = 1;

}

static class IntegerTestThree {

private int i1 = 1;

private int i2 = 1;

private int i3 = 1;

}

static class ReferenceTestOne {

private Object o1 = new Object();

}

static class ReferenceTestTwo {

private Object o1 = new Object();

private Object o2 = new Object();

}

}

一些概念

对象内存 = 对象头 + 类型指针 + 对齐填充

对象头不参与指针压缩,并且 32 位时为 4 个字节,64 位时为 8 个字节

类型指针参与指针压缩,并且 32 位时为 4 个字节,64 位时为 8 个字节;指针压缩时 64 位为 4 个字节

对齐填充,由于 jvm 设计内存要为 8 字节的整数倍,所以不足的需要填充。如 对象头和类型指针一共 12 字节,填充后为 16 字节,填充了 4 个字节

测试结果验证上面的假设

其中 (8 + 8) 为对象头和类型指针的字节数

64 位

-XX:-UseCompressedOops

-XX:+UseCompressedOops

Object

8 + 8 = 16 (对象头+类型指针)

8 + 4 + 4 = 16(对象头+压缩的类型指针+对齐填充)

包含一个int

(8 + 8) + 4 + 4 = 24

(8 + 4) + 4 = 16

包含两个int

(8 + 8) + 4*2 = 24

(8 + 4) + 4*2 + 4 = 24

包含三个int

(8 + 8) + 4*3 + 4 = 32

(8 + 4) + 4*3 = 24

不压缩引用占 8 个字节,压缩占 4 个字节

包含一个引用

(8 + 8) + 8 = 24

(8 + 4) + 4 = 16

包含两个引用

(8 + 8) + 8*2 = 32

(8 + 4) + 4*2 + 4 = 24

静态数据不在对象内存里面

public class MemoryStaticTest {

/**

* -javaagent:{jar包路径}\SizeOfObject.jar

* 使用指针压缩,在一定情况下64位HotSpot jvm默认指针压缩

*

* Output:

* amd64 +UseCompressedOops

* StaticTest: 16

* Integer: 16

* StaticReferenceTest: 16

*

* @param args

*/

public static void main(String[] args) {

System.out.println(System.getProperty("os.arch") + " +UseCompressedOops");

System.out.printf("%-30s%9d\n", "StaticTest:", SizeOfObject.sizeOf(new StaticTest()));

System.out.printf("%-30s%9d\n", "Integer:", SizeOfObject.sizeOf(new Integer(1)));

System.out.printf("%-30s%9d\n", "StaticReferenceTest:", SizeOfObject.sizeOf(new StaticReferenceTest()));

}

static class StaticTest {

private static int i1 = 1;

private static int i2 = 1;

private static int i3 = 1;

private static int i4 = 1;

private static int i5 = 1;

private static int i6 = 1;

}

static class StaticReferenceTest {

private static Object o1 = new Object();

private static Object o2 = new Object();

private static Object o3 = new Object();

private static Object o4 = new Object();

private static Object o5 = new Object();

}

}

为什么是这个样子呢

对象头在 64 位的时候,为什么是 8 个字节;32 位的时候,为什么是 4 个字节

一个引用在 64 位的时候,为什么是 8 个字节;32 位的时候,为什么是 4 个字节

这个跟 C++ 指针有关了,跟寄存器有关了

指针压缩又是怎么个回事

这一切都可以在 jvm 的实现中找到答案,也就是看 C++ 代码。只是我还没到这个阶段=。=

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值