学过c++的朋友想必对“c++的内存对齐规则”不会感到陌生。那么在java中,是否也存在这样的规则呢?为此,笔者进行了实验,发现java的内存对齐规则非常简明——8字节对齐。现与大家分享下。
一个java对象所占的内存空间分为三个部分:对象头(Mark Word+类型指针+长度)+实例数据+填充。
填充的目的是保证一个java对象的大小是8B的整数倍。
对象头分为三个部分:Mark Word、类型指针和长度。这三个部分所占内存空间大小如下所示:
项目 | 占用的内存大小 | 说明 |
---|---|---|
Mark Word | 4B/32位, 8B/64位 | |
类型指针 | 4B/32位, 8B/64位 | |
长度 | 4B/32位, 8B/64位 | 仅数组对象才会有这一部分 |
接下来说一下实例数据包括哪些。静态成员变量或静态成员常量是属于整个类的,存储在方法区,所以不包括在内;当前类所实现接口中的常量,是静态的,同样存储在方法区,不包括在内;所有的方法,不管是静态的还是非静态的,也存储在方法区,不包括在内。剩下的实例成员变量或实例成员常量(包括其祖先类的)就是每个对象要存储的数据 。这些实例成员所占的内存空间大小如下所示:
类型 | 占用的内存大小 | 说明 |
---|---|---|
boolean | 1B | 与平台无关 |
byte | 1B | 与平台无关 |
short | 2B | 与平台无关 |
char | 2B | 与平台无关 |
int | 4B | 与平台无关 |
float | 4B | 与平台无关 |
long | 8B | 与平台无关 |
double | 8B | 与平台无关 |
reference | 4B/32位,8B/64位 |
具体计算方式如下:
假设当前类为B,其父类为A3,类A3的父类为A2,类A2的父类为A1,类A1的父类是Object,且类B, A3, A2, A1都仅有一个char c;
成员变量(当然,这仅仅是举例说明而已,实际情况下可更复杂或更简单),用S_XXX表示类XXX中实例成员的总大小(不包括其祖先类的)。那么类B的一个对象b所占据的内存大小(包括祖先类的)sizeof_b为:
sizeof_b=对象头+(S_A1+填充S_A1)+(S_A2+填充S_A2)+(S_A3+填充_S_A3)+(S_B+填充_S_B)。
“填充_S_XXX”的目的是保证从“对象头”到类XXX部分之和为8B的整数倍。注意看啊,这里每个类都是要填充的,而不是仅在最后才填充,这样做也方便强制类型转换后的处理。而且类XXX中成员变量的声明顺序不影响“S_XXX”的值。
上述类B的一个对象b所占用的内存结构图(32位机器上)如下所示:
又比如“new int[4]
”这个对象在32位机器上所占用的内存为:
再比如这个对象在32位机器上所占用的内存情况为:
下面给出笔者的实验步骤。先是编写两个类SizeOfObjectTest和SizeOfAgent;然后将代码(使用Ant工具)打成可执行的jar包(如 jvm-project.jar,主类是SizeOfObjectTest),最后在命令行里输入如下命令运行该jar包即可查看结果:
java -javaagent:jvm-project.jar -XX:-UseCompressedOops -jar jvm-project.jar
本文仅仅讨论未使用指针压缩情况下的占用内存大小情况。
类SizeOfAgent的编写以及运行方式均是参考http://yueyemaitian.iteye.com/blog/2033046。
下面分别给出SizeOfObjectTest类、SizeOfAgent类和打包脚本。
SzieOfObjectTest类的代码:
package quote;
import java.io.File;
/**
* @author tianmai.fh
* @date 2014-03-18 20:17
*/
public class SizeOfObjectTest {
/**
*
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + padding/0 = 24
*/
static class A {
int a;
char c;
}
static class A2{
char b;
int a;
}
static class A3{
char b;
boolean c;
double d;
short e;
boolean f;
}
static class A4{
char b;
short e;
boolean d;
boolean f;
double a;
}
static class A5{
int[] b=new int[10];
}
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24
*/
static class B {
int a;
int b;
}
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 +