【问题标题】:JVM first 4 booleans optimized, not 5thJVM 前 4 个布尔值优化,而不是第 5 个
【发布时间】:2014-09-12 14:24:42
【问题描述】:

我目前正在使用 Eclipse 内存分析器插件(使用标准 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 个布尔值不知何故被塞进了对象标题中,这是怎么回事?

注意:使用 Oracle JDK1.7 和 JDK1.8 进行测试,64 位,在 Linux x64 上运行。

【问题讨论】:

  • 分析boolean 是一个非常糟糕的主意,因为它们是唯一具有非固定字节大小的原语。
  • 默认情况下-XX:ObjectAlignmentInBytes=8这种简化的对象分配,但是对于小对象它可以有很大的填充。

标签: java memory jvm micro-optimization


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    在 64 位 HotSpot JVM 中使用 CompressedOops

    • 对象头由 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

    【讨论】:

      【解决方案3】:

      我没有看到你是什么。使用来自 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 个字节。

      【讨论】:

        猜你喜欢
        • 2016-08-15
        • 2018-09-15
        • 1970-01-01
        • 2013-02-01
        • 2011-09-13
        • 2020-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多