我目前正在使用Eclipse Memory Analyzer插件(使用标准的jconsole hprof 转储)分析一些Java应用程序,我注意到计算对象大小有一些奇怪的结果:
private static class B1 extends B {
} // 16 bytes
private static class B2 extends B {
boolean d1;
boolean d2;
boolean d3;
boolean d4;
} // also 16 bytes!
private static class B3 extends B {
boolean d1;
boolean d2;
boolean d3;
boolean d4;
boolean d5;
} // 24 bytes
显然前4个布尔值以某种方式被塞在对象标题中,这是怎么回事?
注意:在Linux x64上运行的Oracle JDK1.7和64位JDK1.8进行了测试。
答案 0 :(得分:5)
没有进行优化;对象头通常是8或12字节大,具体取决于VM和模式(压缩OOPS开/关)。通常,内存粒度为8个字节(内存中的对象大小必须总是是粒度的倍数)。
您的结果清楚地表明您的VM使用12字节标头;因此,由于粒度而没有增加对象内存占用空间,因此有4个字节的空间。布尔值通常表示为字节;所以在你的情况下添加第5个需要17个字节(12个标题+ 5个字节)四舍五入到下一个粒度8边界给出24个字节。
答案 1 :(得分:3)
带有CompressedOops的64位HotSpot JVM
markWord
+ 4字节instanceKlass
引用boolean
字段占用1个字节那是
align8(8 + 4) = 16 bytes
align8(8 + 4 + 4*1) = 16 bytes
align8(8 + 4 + 5*1) = align8(17) = 24 bytes
答案 2 :(得分:1)
我没看到你是什么。使用来自Netbeans的1.8:
public static class C1 {
boolean a,b,c,d;
}
public static class C2 {
boolean a,b,c,d,e;
}
public static void main(String[] args) {
try {
Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
unsafeConstructor.setAccessible(true);
Unsafe unsafe = unsafeConstructor.newInstance();
String[] fieldNames = new String[] {"a","b","c","d"};
for (String fieldName : fieldNames) {
System.out.println(fieldName+": "+unsafe.objectFieldOffset(C1.class.getDeclaredField(fieldName)));
}
}
catch(Exception e) {
e.printStackTrace();
}
}
产生结果
a: 12
b: 13
c: 14
d: 15
...表示每个布尔值占用对象中的单独字节偏移量。标头是12个字节。