文章目录

  • 1 JOL
  • 2 对象大小计算
  • 2.1 只开启普通指针压缩
  • 2.2 开启普通指针压缩和开启类指针压缩
  • 2.3 不开启压缩
  • 2.4 计算总结
  • 2.5 加餐


1 JOL

JOL(Java Object Layout),是openjdk的一个工具,可以查看详细的对象布局。

<dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.16</version>
        </dependency>

把包引入到项目中,放一段测试用的代码

import org.openjdk.jol.info.ClassLayout;

import java.util.List;

/**
 * @author 编程还未
 */
public class TestJOL {
    public static void main(String[] args) {
        User user = new User();
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }

    static class User {
        byte a;
        short b;
        int c;
        long d;
        float e;
        double f;
        boolean g;
        char h;
        String i;
        Child child;
        List<Child> childList;
    }

    static class Child {
        String name;
    }
}

开启指针压缩(-XX:+UseCompressedOops)运行结果如下:

com.program_highway.TestJOL$User object internals:
OFF  SZ                                TYPE DESCRIPTION               VALUE
  0   8                                     (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                                     (object header: class)    0x00c01200
 12   4                                 int User.c                    0
 16   8                                long User.d                    0
 24   8                              double User.f                    0.0
 32   4                               float User.e                    0.0
 36   2                               short User.b                    0
 38   2                                char User.h                     
 40   1                                byte User.a                    0
 41   1                             boolean User.g                    false
 42   2                                     (alignment/padding gap)   
 44   4                    java.lang.String User.i                    null
 48   4   com.program_highway.TestJOL.Child User.child                null
 52   4                      java.util.List User.childList            null
Instance size: 56 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total

关闭指针压缩(-XX:-UseCompressedOops)运行结果如下:

com.program_highway.TestJOL$User object internals:
OFF  SZ                                TYPE DESCRIPTION               VALUE
  0   8                                     (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                                     (object header: class)    0x00c01200
 12   4                                 int User.c                    0
 16   8                                long User.d                    0
 24   8                              double User.f                    0.0
 32   4                               float User.e                    0.0
 36   2                               short User.b                    0
 38   2                                char User.h                     
 40   1                                byte User.a                    0
 41   1                             boolean User.g                    false
 42   6                                     (alignment/padding gap)   
 48   8                    java.lang.String User.i                    null
 56   8   com.program_highway.TestJOL.Child User.child                null
 64   8                      java.util.List User.childList            null
Instance size: 72 bytes
Space losses: 6 bytes internal + 0 bytes external = 6 bytes total

2 对象大小计算

对象大小=对象头+实例数据

本小节内的运行结果,还是用JOL中的Java示例,Java1.8版本

alignment/padding gap:对齐/填充间隙(基本数据类型用的)。单个对象内部的成员变量填充对齐。开启指针压缩按4的倍数补齐;关闭指针压缩按8的倍数补齐。因为对象内部的引用类型要么4bytes要么8bytes,所以说这个属性是基本数据类型对齐用的,下面不再重复解释。

object alignment gap:对象对齐间隙。单个对象内部整体按8的倍数对齐。

-XX:+UseCompressedOops:普通指针压缩。64位HotSpot VM1.6 update14 开始正式支持。会把对象内的普通对象实例由8 bytes(64位)压缩到4 bytes(32位)。

-XX:+UseCompressedClassPointers:HotSpot会把对象头中_metadata指向klass的指针压缩为一个无符号32位整数,4bytes。

2.1 只开启普通指针压缩

JVM参数:-XX:+UseCompressedOops -XX:-UseCompressedClassPointers

com.program_highway.jol.TestJOL$User object internals:
OFF  SZ                                    TYPE DESCRIPTION               VALUE
  0   8                                         (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   8                                         (object header: class)    0x00000266a13836e8
 16   8                                    long User.d                    0
 24   8                                  double User.f                    0.0
 32   4                                     int User.c                    0
 36   4                                   float User.e                    0.0
 40   2                                   short User.b                    0
 42   2                                    char User.h                     
 44   1                                    byte User.a                    0
 45   1                                 boolean User.g                    false
 46   2                                         (alignment/padding gap)   
 48   4                        java.lang.String User.i                    null
 52   4   com.program_highway.jol.TestJOL.Child User.child                null
 56   4                          java.util.List User.childList            null
 60   4                                         (object alignment gap)    
Instance size: 64 bytes
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

该情况下计算:

对象大小=对象头+实例数据

对象大小=64 bytes

对象头=16 bytes,包含:object header: mark 8 bytes 和 object header: class 8 bytes

实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,补齐补2个bytes,32 bytes;引用类型的大小=4+4+4=12 bytes;

最终结果:对象大小(64 byets)=对象头(16bytes)+实例数据【基础类型(32bytes)+引用类型(12bytes)】+ 对象对齐间隙(4 bytes)

2.2 开启普通指针压缩和开启类指针压缩

JVM参数:-XX:+UseCompressedOops -XX:+UseCompressedClassPointers

注意:-XX:+UseCompressedClassPointers参数依赖-XX:+UseCompressedOops

这是JVM1.8默认的配置,两个压缩都开启。

com.program_highway.jol.TestJOL$User object internals:
OFF  SZ                                    TYPE DESCRIPTION               VALUE
  0   8                                         (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                                         (object header: class)    0xf800c143
 12   4                                     int User.c                    0
 16   8                                    long User.d                    0
 24   8                                  double User.f                    0.0
 32   4                                   float User.e                    0.0
 36   2                                   short User.b                    0
 38   2                                    char User.h                     
 40   1                                    byte User.a                    0
 41   1                                 boolean User.g                    false
 42   2                                         (alignment/padding gap)   
 44   4                        java.lang.String User.i                    null
 48   4   com.program_highway.jol.TestJOL.Child User.child                null
 52   4                          java.util.List User.childList            null
Instance size: 56 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total

该情况下计算

对象大小=对象头+实例数据

对象大小=56 bytes

对象头=12 bytes,包含:object header: mark 8 bytes 和 object header: class 4 bytes

实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,补齐补2个bytes,32 bytes;引用类型的大小=4+4+4=12 bytes;

最终结果:对象大小(64 bytes)=对象头(12 bytes)+实例数据【基础类型(32 bytes)+引用类型(12 bytes)】

能被8整除,就不需要补齐了。

2.3 不开启压缩

JVM参数:-XX:-UseCompressedOops -XX:-UseCompressedClassPointers

com.program_highway.jol.TestJOL$User object internals:
OFF  SZ                                    TYPE DESCRIPTION               VALUE
  0   8                                         (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   8                                         (object header: class)    0x000001c320aa36e8
 16   8                                    long User.d                    0
 24   8                                  double User.f                    0.0
 32   4                                     int User.c                    0
 36   4                                   float User.e                    0.0
 40   2                                   short User.b                    0
 42   2                                    char User.h                     
 44   1                                    byte User.a                    0
 45   1                                 boolean User.g                    false
 46   2                                         (alignment/padding gap)   
 48   8                        java.lang.String User.i                    null
 56   8   com.program_highway.jol.TestJOL.Child User.child                null
 64   8                          java.util.List User.childList            null
Instance size: 72 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total

该情况下计算

对象大小=对象头+实例数据

对象大小=72 bytes

对象头=16 bytes,包含:object header: mark 8 bytes 和 object header: class 4 bytes

实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,8位补齐补2个bytes,32 bytes;引用类型的大小=8+8+8=24 bytes;

最终结果:对象大小(72 byets)=对象头(16 bytes)+实例数据【基础类型(32 bytes)+引用类型(24 bytes)】

能被8整除,就不需要补齐了。

2.4 计算总结

对象大小受三个JVM属性的影响,上述两个-XX:+/-UseCompressedOops -XX:+/-UseCompressedClassPointers,还有-XX:+/-CompactFields

-XX:+/-UseCompressedOops:开启/关闭普通指针压缩

-XX:+/-UseCompressedClassPointers:开启/关闭类指针压缩

-XX:+/-CompactFields:开启/关闭紧凑属性,

这三个属性默认都是开启的,在默认情况下计算对象大小。

对象大小=对象头+实例数据+object alignment gap(对象对齐间隙)

对象头=12 bytes

实例数据=基础数据类型占用之和+alignment/padding gap(对齐/填充缝隙)+引用类型占用之和(一个对象占4 bytes)+object alignment gap(对象对齐间隙)

2.5 加餐

有继承关系如何处理?(默认三个属性都开启)

如果上述类User有继承关系且父类有属性,User类会有父类的属性,父类的基本数据类型会单独计算。

Father类,User类继承Father

static class Father {
        private String address;
        short age;
    }

结果:

com.program_highway.jol.TestJOL$User object internals:
OFF  SZ                                    TYPE DESCRIPTION               VALUE
  0   8                                         (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                                         (object header: class)    0xf800c182
 12   2                                   short Father.age                0
 14   2                                         (alignment/padding gap)   
 16   4                        java.lang.String Father.address            null
 20   4                                     int User.c                    0
 24   8                                    long User.d                    0
 32   8                                  double User.f                    0.0
 40   4                                   float User.e                    0.0
 44   2                                   short User.b                    0
 46   2                                    char User.h                     
 48   1                                    byte User.a                    0
 49   1                                 boolean User.g                    false
 50   2                                         (alignment/padding gap)   
 52   4                        java.lang.String User.i                    null
 56   4   com.program_highway.jol.TestJOL.Child User.child                null
 60   4                          java.util.List User.childList            null
Instance size: 64 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

有继承关系的对象大小=对象头+父基本数据类型占用大小+父基本数据类型的alignment/padding gap(对齐/填充缝隙)+ 自己的基本数据类型占用大小+自己的基本数据类型的alignment/padding gap(对齐/填充缝隙)+ 父类和自己的引用类型占用之和(一个对象占4 bytes)