JVM优先4个布尔优化,而不是第5个

时间:2014-09-12 14:24:43

标签: java memory jvm micro-optimization

我目前正在使用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进行了测试。

3 个答案:

答案 0 :(得分:5)

没有进行优化;对象头通常是8或12字节大,具体取决于VM和模式(压缩OOPS开/关)。通常,内存粒度为8个字节(内存中的对象大小必须总是是粒度的倍数)。

您的结果清楚地表明您的VM使用12字节标头;因此,由于粒度而没有增加对象内存占用空间,因此有4个字节的空间。布尔值通常表示为字节;所以在你的情况下添加第5个需要17个字节(12个标题+ 5个字节)四舍五入到下一个粒度8边界给出24个字节。

答案 1 :(得分:3)

带有CompressedOops的64位HotSpot JVM

  • 对象标头由8字节markWord + 4字节instanceKlass引用
  • 组成
  • boolean字段占用1个字节
  • 对象是8字节对齐

那是

  • 空对象占用align8(8 + 4) = 16 bytes
  • 具有4个布尔字段的对象占用align8(8 + 4 + 4*1) = 16 bytes
  • 具有5个布尔字段的对象占用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个字节。