java对象大小_Java对象结构及大小计算

jvm系列

本文主要简述Java对象的内存布局以及其大小的计算。

Java对象内存布局

8a28b21379d1d82ae4356042d82eb0b3.png

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

对象头

HotSpot虚拟机的对象头包括两部分信息:

第一部分markword,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为“MarkWord”。

对象头的另外一部分是klass,类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.

实例数据

实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。

对齐填充

第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

对象大小计算

要点

在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。

在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。

64位开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。

数组长度4字节+数组对象头8字节(对象引用4字节(未开启指针压缩的64位为8字节)+数组markword为4字节(64位未开启指针压缩的为8字节))+对齐4=16字节。

静态属性不算在对象大小内。

实例

import java.util.HashMap;

/**

* 64位开启指针压缩的话,markword变成8字节,压缩了class指针为4字节,故对象头12字节

* 64位没有开启指针压缩的话,markword8字节,class指针8字节,对象头16字节

* 32位markword为4字节,class指针为4字节,对象头8字节

*

* 另外,静态属性所占用的空间通常不算在对象本身,因为它的引用是在方法区。

*

* @author xixicat

* @created 2014-10-03

*/

public class ObjectSize {

public static void main(String[] args){

System.out.println(SizeOfTool.getObjectSize(new A(),SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new B(),SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new C(),SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new D(),SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new E(),SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new Q(),SizeEnum.B));

/**

* 64位压缩指针下,对象头12字节,数组长度描述4字节,数据4*100 =16+400 = 416

*/

System.out.println(SizeOfTool.getObjectSize(new int[100],SizeEnum.B));

/**

* 属性4位对齐

* 64位压缩指针下,对象头12字节,数组长度描述4字节,数据1*100,对齐后104 = 16+104 = 120

*/

System.out.println(SizeOfTool.getObjectSize(new byte[100],SizeEnum.B));

/**

* 二维数组

* 64位指针压缩下

* 第1维数组,对象头12字节,数组长度描述4字节,2个数组引用共8字节,共24字节

* 第2维数组,对象头12字节,数组长度描述4字节,100个数组引用共400字节,对齐后共416字节

* 第1维的2个引用所指对象大小 = 2*416 = 832 字节

* 共24+832 = 856字节

*/

System.out.println(SizeOfTool.getObjectSize(new int[2][100],SizeEnum.B));

/**

* 二维数组

* 64位指针压缩下

* 第1维数组,对象头12字节,数组长度描述4字节,100个数组引用共400字节,共416字节

* 第2维数组,对象头12字节,数组长度描述4字节,2个数组引用共8字节,共24字节

* 第1维的100个引用所指对象大小 = 100*24 = 2400 字节

* 共416+2400 = 2816字节

*/

System.out.println(SizeOfTool.getObjectSize(new int[100][2],SizeEnum.B));

System.out.println(SizeOfTool.getObjectSize(new Object(),SizeEnum.B));

/**

* 不算static属性

* private final char value[];

* private int hash; // Default to 0

* private transient int hash32 = 0;

*

* 32位下,String对象头8字节,2个int类型8字节,char数组引用占4字节,共占24字节

* 另外,还要算上value[]数组的占用,数组对象头部8字节,数组长度4字节,对齐后共占16字节

* =》String对象对象大小24+16 = 40字节

* 64位开启指针压缩下(压缩指针),String对象头12字节,2个int类型8字节,char数组引用占4字节,共占24字节

* 另外,还要算上value[]数组的占用,数组对象头部12字节,数组长度4字节,对齐后共占16字节

* =》String对象大小24+16=40字节

*/

System.out.println(SizeOfTool.getObjectSize(new String(),SizeEnum.B));

/**

* transient Entry[] table = (Entry[]) EMPTY_TABLE;

* transient int size;

* int threshold;

* final float loadFactor;

* transient int modCount;

*

* 64位开启指针压缩下,对象头部12字节,数组引用4字节,3个int12字节,float4字节,共32字节

* 另外,算上Entry[] = 对象头12 +属性16字节+数组长度4字节 = 32字节

*

* final K key;

* V value;

* Entry next;

* int hash;

*

* 对象头12字节,3个引用共12字节,1个int4字节 =》 一个entry至少占用28字节

*

* =》32+32=64字节

*/

System.out.println(SizeOfTool.getObjectSize(new HashMap(),SizeEnum.B));

}

}

//32位下对象头8字节,byte占1字节,对其填充后,总占16字节

//64位开启指针压缩下对象头12字节,byte1字节,对齐后占16字节

class A{

byte b1;

}

//32位下对象头8字节,8个byte8字节,总16字节

//64位开启指针压缩下对象头12字节,8个byte8字节,对齐后占24字节

class B{

byte b1,b2,b3,b4,b5,b6,b7,b8;

}

//32位下对象头8字节,9个byte9字节,对其填充后,总24字节

//64位开启指针压缩下对象头12字节,9个byte9字节,对齐后占24字节

class C{

byte b1,b2,b3,b4,b5,b6,b7,b8,b9;

}

//32位下对象头8字节,int占4字节,引用占4字节,共16字节

//64位开启指针压缩下对象头12字节,int占4字节,引用占4字节,对齐后占24字节

class D{

int i;

String str;

}

//32位下对象头8字节,int4字节,byte占1字节,引用占4字节,对其后,共24字节

//64位开启指针压缩下对象头12字节,int占4字节,引用占4字节,byte占1字节,对齐后占24字节

class E{

int i;

byte b;

String str;

}

/**

* 对齐有两种

* 1、整个对象8字节对齐

* 2、属性4字节对齐 ****

*

* 对象集成属性的排布

* markword 4 8

* class指针 4 4

* 父类的父类属性 1 1

* 属性对齐 3 3

* 父类的属性 1 1

* 属性对齐 3 3

* 当前类的属性 1 1

* 属性对齐填充 3 3

* 整个对象对齐 8+12 =》 24 12+12=》24

*/

class O{

byte b;

}

class P extends O{

byte b;

}

class Q extends P{

byte b;

}

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值