java 解压到内存_Java 对象在内存

平常工作中,我们只new一个对象,却基本不关心这个对象到底占了我们多少空间.

今天就一起看下,对象的空间占用情况

首先,内存中的对象是由以下几部分构成的:

a423ba4d3b962508718f1e50455f2d0e.png

结合上图以下类为例,看下内存空间的占用情况

public class MyObject {    int i = 123;    long l = 234;    String str = "12345";}

1. Mark word: 记录线程,锁等对象状态,64位机占用8字节;32位机占用4字节; 当前主机是64位占8字节

2. Klass pointer: 指向类元数据的指针,开启指针压缩时, 占4字节;

3. 数组长度: 如果是数组对象,存储数组长度,如果不是数组,没有该区域;

4. 头部数据补全: 只是在关闭指针压缩,并且是数组对象的情况下才会用到;

5. 实例属性: 存储实例属性; 例如:int变量4字节; long变量8字节; String对象是一个指针占4字节;

6. 对齐补全: JVM中开辟的内存空间必须是8字节的倍数, 如果缺少位数,需要补全为8的倍数; 以上各字段共28字节,需补全4字节

所以MyObject对象共占用8+4+0+16+4=32字节

下面利用openjdk的jol工具包验证下

public static void main(String[] args) {    MyObject object = new MyObject();    System.out.println(ClassLayout.parseInstance(object).toPrintable());}

执行结果:

MyObject object internals: OFFSET  SIZE               TYPE DESCRIPTION                               VALUE      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4                    (object header)                           05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)     12     4                int MyObject.i                                123     16     8               long MyObject.l                                234     24     4   java.lang.String MyObject.str                              (object)     28     4                    (loss due to the next object alignment)Instance size: 32 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

和我们预期是一样,共占用32字节,有4字节的空间损失.

数组结构内存空间

再看下数组结构的内存空间分配

public static void main(String[] args) {    MyObject[] array = new MyObject[]{new MyObject(),new MyObject()};    System.out.println(ClassLayout.parseInstance(array).toPrintable());}

对象头部分除MarkWord和klass pointer以外, 还有4字节用来存储数组长度

[LMyObject; object internals: OFFSET  SIZE       TYPE DESCRIPTION                               VALUE      0     4            (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4            (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4            (object header)                           d1 c4 00 f8 (11010001 11000100 00000000 11111000) (-134167343)     12     4            (object header)                           02 00 00 00 (00000010 00000000 00000000 00000000) (2)     16     8   MyObject [LMyObject;.                    N/AInstance size: 24 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

其他类型的实例属性

再看看其他属性的内存占用情况是如何的.

public class OtherObject {    public static final float PI = 3.14f;    boolean b = false;    char c = 'a';    short s = 20;    int i = 123;    long l = 234;    float f = 0.1f;    double d = 0.2d;    String str = "12345";    Map map = new HashMap();    Set set = new HashSet();    List list = new ArrayList();    public static void main(String[] args) {        OtherObject object = new OtherObject();        object.map.put("a", "a");        object.set.add("a");        object.list.add("a");        System.out.println(ClassLayout.parseInstance(object).toPrintable());        System.out.println(ClassLayout.parseInstance(object).headerSize());        System.out.println(ClassLayout.parseInstance(object).instanceSize());    }}

通过执行结果可以发现:

类变量是不用开辟内存空间的

boolean类型占用1个字节,后面需要3字节对齐补全;

short和char类型都需要2字节的空间, 但JVM进行了优化,并不需增加空间对齐补全;

在最后需要4字节对齐补全;

整个对象需要64字节,空间损失了7字节.

OtherObject object internals: OFFSET  SIZE               TYPE DESCRIPTION                               VALUE      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4                    (object header)                           05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)     12     4                int OtherObject.i                             123     16     8               long OtherObject.l                             234     24     8             double OtherObject.d                             0.2     32     4              float OtherObject.f                             0.1     36     2               char OtherObject.c                             a     38     2              short OtherObject.s                             20     40     1            boolean OtherObject.b                             false     41     3                    (alignment/padding gap)                       44     4   java.lang.String OtherObject.str                           (object)     48     4      java.util.Map OtherObject.map                           (object)     52     4      java.util.Set OtherObject.set                           (object)     56     4     java.util.List OtherObject.list                          (object)     60     4                    (loss due to the next object alignment)Instance size: 64 bytesSpace losses: 3 bytes internal + 4 bytes external = 7 bytes total

指针压缩

指针压缩是指在64位机上,也使用32位表示引用地址.

在上面的例子中都是开启指针压缩的,因为从jdk6之后就是默认开启的.

共涉及到2个JVM参数

-XX:+UseCompressedOops

会使用4字节来表示java object的引;

默认开启

-XX:+UseCompressedClassesPointers

默认开启

用4字节来表示进程中的class pointer;

UseCompressedClassPointers的开启是依赖于UseCompressedOops的开启.

同样是MyObject对象,在关闭指针压缩时,共需要40字节的空间

Mark down使用8字节

Klass pointer 使用8字节

str指针也占用8字节;

MyObject object internals: OFFSET  SIZE               TYPE DESCRIPTION                               VALUE      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4                    (object header)                           28 30 60 a2 (00101000 00110000 01100000 10100010) (-1570754520)     12     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)     16     8               long MyObject.l                                234     24     4                int MyObject.i                                123     28     4                    (alignment/padding gap)                       32     8   java.lang.String MyObject.str                              (object)Instance size: 40 bytesSpace losses: 4 bytes internal + 0 bytes external = 4 bytes total

指针压缩的好处

1. 节省内存空间

2. 提升执行效率

头部空间补全

在关闭指针压缩之后,在看数组对象的内存空间,就可以发现产生了数据补全的情况

Mark down使用8字节

Klass pointer 使用8字节

数组长度 使用4字节

头部数据补全 使用4字节

[LMyObject; object internals: OFFSET  SIZE       TYPE DESCRIPTION                               VALUE      0     4            (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4            (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4            (object header)                           00 3a c2 0c (00000000 00111010 11000010 00001100) (214055424)     12     4            (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)     16     4            (object header)                           02 00 00 00 (00000010 00000000 00000000 00000000) (2)     20     4            (alignment/padding gap)                       24    16   MyObject [LMyObject;.                    N/AInstance size: 40 bytesSpace losses: 4 bytes internal + 0 bytes external = 4 bytes total

以上,就是一个对象内存的占用情况.

最后,附上openjdk.jol的maven依赖

    org.openjdk.jol    0.9    jol-cli

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值