脚本宝典收集整理的这篇文章主要介绍了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
-
在运行测试程序的时候,添加 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%9dn", "Object:", SizeOfObject.sizeOf(new Object()));
System.out.println();
System.out.printf("%-30s%9dn", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne()));
System.out.printf("%-30s%9dn", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo()));
System.out.printf("%-30s%9dn", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree()));
System.out.println();
System.out.printf("%-30s%9dn", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne()));
System.out.printf("%-30s%9dn", "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%9dn", "Object:", SizeOfObject.sizeOf(new Object()));
System.out.println();
System.out.printf("%-30s%9dn", "include one int:", SizeOfObject.sizeOf(new IntegerTestOne()));
System.out.printf("%-30s%9dn", "include two int:", SizeOfObject.sizeOf(new IntegerTestTwo()));
System.out.printf("%-30s%9dn", "include three int:", SizeOfObject.sizeOf(new IntegerTestThree()));
System.out.println();
System.out.printf("%-30s%9dn", "include one object:", SizeOfObject.sizeOf(new ReferenceTestOne()));
System.out.printf("%-30s%9dn", "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%9dn", "StaticTest:", SizeOfObject.sizeOf(new StaticTest()));
System.out.printf("%-30s%9dn", "Integer:", SizeOfObject.sizeOf(new Integer(1)));
System.out.printf("%-30s%9dn", "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();
}
}
- 代码中还有一点其他测试: https://github.com/Deeeeeeeee/jcoding.git
为什么是这个样子呢
- 对象头在 64 位的时候,为什么是 8 个字节;32 位的时候,为什么是 4 个字节
-
一个引用在 64 位的时候,为什么是 8 个字节;32 位的时候,为什么是 4 个字节
- 这个跟 C++ 指针有关了,跟寄存器有关了
- 指针压缩又是怎么个回事
这一切都可以在 jvm 的实现中找到答案,也就是看 C++ 代码。只是我还没到这个阶段=。=
参考链接
以上是脚本宝典为你收集整理的java 对象内存大小全部内容,希望文章能够帮你解决java 对象内存大小所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。