java 对象实例数据 实战

本文探讨了Java对象在内存中的布局细节,包括对象头、实例数据和填充的作用,并通过实验对比了压缩指针开关状态下的内存占用变化。

实验对象代码



public class MyTest {

    private String name;

    private Integer age;

    private Long money;

    private long high = 7L;

    private char sex = 'a';

    private boolean flag = true;

    private int num = 0x12345678;

    private long leg = 9L;

public int test(int a){

    a = 3;

return a;

}

    public static void main(String[] args){

        

        int a = 0;

        a = a + 1;

MyTest mytest = new MyTest();

      
mytest.money = 1000L;

    for(;;){}

 

}    

}

一、Java对象在内存中布局是什么样的?-XX:-UseCompressedOops 压缩指针以及数据类型对排列顺序是否影响?对齐填充填充的是哪里?

启动命令:

java -Djava.compiler=NONE -XX:-UseCompressedOops MyTest

     

实验类MyTest ;64位HotSpot虚拟机;关闭压缩指针情况下 -XX:-UseCompressedOops

对象头大小 = 8 + 8 = 16

对象实例数据大小 = 8(指针name) + 8 (指针age) + 8 (指针money) + 8 (long类型high)+ 2(char类型sex) + 1(boolean类型) + 4(int类型num) + 8 (long类型 leg)= 47

对象实际大小 = 16 + 47 + 1(填充) = 64

通过HSDB 查看

              

注:左边图1是对象Oop ;右图2是该对象在内存中的排列,左边一列是内存地址,右边是内存中存的值

可以看到 该对象一共占了64个字节

第一行 0x0000025c1f00b070: 0x0000000000000001 (这个对象头markword好像存的是线程id)

第二列 0x0000025c1f00b078: 0x0000025c7cbb0630 (对象Klass指针,指向对象Klass内存地址)

第三列 0x0000025c1f00b080: 0x0000000000000007 (long数据类型high 的值,占8个字节)

第四行 0x0000025c1f00b088: 0x0000000000000009 (long数据类型leg 的值,占8个字节)

第五行 0x0000025c1f00b090: 0x0001006112345678  (这八个字节存储了三部分数据,从右到左的4个字节 12345678存的是int类型num值;紧跟后的2个字节 61 是char类型sex存的值'a' ascill码 97;再跟后面一个字节01 是boolean类型flag 存的true;再后面一个字节是填充数据)

第六行 0x0000025c1f00b098: 0x0000000000000000 (指针name 从图三的偏移位置40可看出)

第七行 0x0000025c1f00b0a0: 0x0000000000000000(指针age 从图三的偏移位置48可看出)

第八行 0x0000025c1f00b0a8: 0x0000025c1f00b880 (最后一列是指针Money指向的Long对象内存地址)

实验结果:1. 对象排列和数据类型有关,基本类型会在引用类型前面

                 2. 对齐填充是在某个数据类型不足8字节而填充至8字节

                 3. 64位Hotspot虚拟机,klass未开启压缩指针占 8 字节

二、开启压缩指针

启动命令

java -Djava.compiler=NONE -XX:+UseCompressedOops MyTest

实验类MyTest ;64位HotSpot虚拟机;开启压缩指针情况下 -XX:-UseCompressedOops

对象头大小 = 8 + 4(Klass压缩为4字节) = 12

对象实例数据大小 = 4(指针name) + 4 (指针age) + 4 (指针money) + 8 (long类型high)+ 2(char类型sex) + 1(boolean类型) + 4(int类型num) + 8 (long类型 leg)= 35

对象实际大小 = 12 + 35 + 1(填充) = 48

  

可以看到这次与关闭压缩指针内存节省了24个字节,对象内部布局及顺序也发生了变化

第一行 0x000000076bbe02a8: 0x0000000000000001 

第二列 0x000000076bbe02b0: 0x12345678f800c005 (分了两部分数据,对象Klass指针4个字节,指向对象Klass内存地址;另一个int类型数据num)

第三列 0x000000076bbe02b8: 0x0000000000000007 (long数据类型high 的值,占8个字节)

第四行 0x000000076bbe02c0: 0x0000000000000009 (long数据类型leg 的值,占8个字节)

第五行 0x000000076bbe02c8: 0x0000000000010061  (这8个字节分为3部分数据,char类型占两个字节,boolean占一个字节,填充一个字节,在跟着指针name的4个字节,根据偏移位置36可以看出)

第六行 0x000000076bbe02d0: 0xed77c12500000000 (这部分分为两部分,开头4字节为指针age, 后面紧跟4字节是指针Money指向的内存地址)

关于压缩指针,我们知道32位机器最大寻址空间是2^32次方,而内存按8位为一字节进行编址,则最大寻址空间就是4G; 同理可得64位机器寻址空间可达到 2^32 * 4 G,但是压缩成

4字节的指针按道理只能寻址4G的地址空间,它是怎么做到寻址最大达到32G空间的?

后面大概了解到,java对象按8字节进行对齐,则可将指针原本按一个字节寻址,现在扩展为8字节来寻址,即原本指针指向 0x100,0x101... ;压缩指针后,0x100, 0x108... 

,同理,你也可以只用一位来寻址64位的机器,只不过就指向这一个地址罢了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值