本文转载自 java对象在内存的大小
java对象在内存中占用的空间分为3类, 1. 对象头(Header); 2. 实例数据(Instance Data); 3. 对齐填充(Padding)。常说的基础数据类型大小主要是指第二类实例数据。
具体示例如下:
import org.openjdk.jol.info.ClassLayout;
public class JOLDemo {
public static void main(String[] args) {
Object o=new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
int a=1;
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
运行结果如下:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 67 22 00 20 (01100111 00100010 00000000 00100000) (536879719)
12 4 int Integer.value 1
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
对象头
HotSpot虚拟机的对象头包括两部分信息:
markword和klass 。第一部分markword,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。 另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
注:如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度,也就是一个int类型的对象,占4字节。
大小问题:
- 在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。
- 在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。 在64位开启指针压缩的情况下。(上面示例展示的情况)其中第一个字节的最低两位为该对象的锁标志位。
- -XX:+UseCompressedOops,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。
- 如果对象是数组,那么额外增加4个字节
实例数据
实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。
对齐填充
最后一块对齐填充空间并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。这是由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。