JAVA字节对齐
一般而言,Java对象不需要考虑字节对齐,JVM编译时会自动优化。但C/C++/C#等需要考虑对象次序,避免空间浪费。(注:本文中使用的jdk版本是1.8为基础的 。)
对象结构
在HotSpot虚拟机中,对象在内存中的存储布局分为三块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)
对象头
- Mark Word:包含一系列的标记位,比如轻量级锁的标记位,偏向锁标记位等等。在32位系统占4字节,在64位系统中占8字节;
- Class Pointer(类型指针):用来指向对象对应的Class对象(其对应的元数据对象)的内存地址。在32位系统占4字节,在64位系统中占8字节;
- Length:如果是数组对象,还有一个保存数组长度的空间,占4个字节;
实例数据
八种基础数据类型及相关引用类型
- byte、boolean是1个字节
- short、char是2个字节
- int、float是4个字节
- long、double是8个字节
- reference是4个字节
对齐方式
64位HotSpot VM每次读取数据的最小单位是8字节,因此对象大小必须保持8字节的整数倍,不足则填充。
关于编码(对比C/C++)
在C/C++中,结构体中不合理属性顺序,会增加对象所需的存储空间。
测试代码
struct Person1 {
char _char;
int _int;
short _short;
};
struct Person2 {
char _char;
short _short;
int _int;
};
int main() {
printf("_person1 sizeof: %d \n", sizeof(Person1));
printf("_person2 sizeof: %d \n", sizeof(Person2));
}
结果
_person1 sizeof: 12
_person2 sizeof: 8
因此,在C/C++编码过程中,合理安排结构体属性的次序是很有必要的。幸运的是JVM会自动调整属性的次序。保证对象所需的存储空间最小。
测试代码
public class Person {
public byte _1_byte;
public int _1_int;
public boolean _boolean;
public int _2_int;
public short _short;
public double _double;
public char _char;
public long _long;
public byte _2_byte;
// 引用类型
public Person2 person2;
}
public class Person2 {
public byte _byte;
public boolean _boolean;
public char _char;
public short _short;
public int _int;
public long _long;
public float _float;
public double _double;
}
public static void main(String[] args) {
Person person = new Person();
String s = ClassLayout.parseInstance(person).toPrintable();
System.out.println(s);
}
结果
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c392
12 4 int Person._1_int 0
16 8 double Person._double 0.0
24 8 long Person._long 0
32 4 int Person._2_int 0
36 2 short Person._short 0
38 2 char Person._char
40 1 byte Person._1_byte 0
41 1 boolean Person._boolean false
42 1 byte Person._2_byte 0
43 1 (alignment/padding gap)
44 4 com.yejing.exercise.bean.Person2 Person.person2 null
Instance size: 48 bytes
Space losses: 1 bytes internal + 0 bytes external = 1 bytes total
可以看出 “_1_byte” 属性的次序被自动调整到靠下的地方,使得小对象相邻,减少空白填充。
另外,经过多组测试,发现JVM在字节对齐的过程中相同大小的对象会按之前的属性次序存储。如 long, double; int,float; byte,boolean。
其他
https://www.163.com/dy/article/G7BGCH720517O4DT.html