对象的内存布局
在java中对象的内存布局分为两种情况,非数组对象和数组对象。数组对象和非数组对象的区别就是需要额外的空间来存储数组长度length。
对象头
对象头又分为Mark Down和Class Pointer两部分。
Mark Down:包含一系列的标记位,比如轻量级锁的标记位,偏向锁标记位,gc记录信息等等,在32位系统占4字节,在64位系统占8字节。
Class Pointer:用来指向对象对应的class对象(其对应的元数据对象)的内存地址。在32位系统占4字节,在64位系统占8字节。
Length:只在数组对象中存在,用来记录数组的长度,占用4字节。
Instance Data:对象实际数据,包含对象的所有成员变量,其大小由各个成员变量的大小决定。(这里不包括静态成员变量,因为其是在方法区维护的)
Padding:Java对象占用空间是8字节对齐的,即所有对象占用bytes数必须是8的倍数,是因为当我们从磁盘中取一个数据时,不会说我想取一个字节就取一个字节,都是按照一块一块来取的,这一块大小是8个字节,所以为了完整,padding的作用就是补充字节,保证对象是8字节的整数倍。
Moon在上文特意标注了32位系统和64位系统不同区域占用空间大小的区别,这是因为对象指针在64位JVM小的寻址更长,所以相比32位会占用更多空间。
但是现在假设一个场景,公司现在项目部署的机器是 32 位的,你们老板要让你将项目迁移到 64 位的系统上,但是又因为 64 位系统比 32 位系统要多出更多占用空间,怎么办,因为正常来说我们是不需要这一部分多余空间的,所以 jvm 已经帮你考虑好了,那就是指针压缩。
指针压缩
-XX:+UseCompressedOops 这个参数就是JVM提供的解决方案,可以压缩指针,将占用的空间压缩为原来的一半,起到节约空间的作用,class pointer参数大小就受此影响。
Object o = new Object()到底占用多少个字节?
我们将针对两种情况分析:
1)在开启指针压缩的情况下,markdown占用8字节,classpointer占用4字节,总共是 12 字节,由于对象需要为 8 的整数倍,Padding 会补充 4 个字节,总共占用 16 字节的存储空间。
2)在没有指针的情况下,markword 占用 8 字节,classpoint 占用 8 字节,Interface data 无数据,总共是 16 字节。
补充:
对象创建过程(基于Hotspot VM分代模型)
文章摘自微信公众号《moon聊技术》