第二节对象在内存中的布局及对象创建过程

         理解对象的布局和对象的创建过程有助于理解锁和构造器的执行时机。对象在堆中的分布包含三部分:对象头,实例数据,填充区域。以下分别详细介绍。

      对象头:对象头的数据结构是不是固定的,它会根据对象的状态动态的变化。对象都得大小时32bit/ 64bit(取决于你的系统是多少位的),里边存储了对象的hashcode,分代年龄,对象锁等信息,其中比较常用的是hashcode和锁信息。

      实例数据:这里存储的是对象的实际使用的数据(即对象中的字段和方法)。

       填充区:这个区基本没啥用,主要是为了优化JVM时使用的。因为JVM要求对象的在内存中的起始地址是8bit的倍数,若不是8的倍数就使用这个区进行填充已满足要求。

      对象的创建过程:对象的创建可以细分为三个过程

                                      (1)JVM解析到new命令时,会判断它的参数(即构造器)在常量池中是否有对应的类的符号引用,如果没有就要加载、解析和初始化(类的加载机制后边会有);                                      

                                     (2)如果有,就在堆上分配确定大小的内存空间(对象的大小有类的大小决定);然后将对象的内存空间全部设置为零,然后设置对象的对象头,包括设置对象的hashCode、分带年龄等(此处有个问题,如果没有重写Object的hashCode()方法,那么hashcode 此时可以确定;如果重写了,此时hashcode值应该是要么与没有重写时一样,要么就是按字段的默认初始值来计算  ---个人猜想)。

                                      (3)到此为止,对于jvm而言,对象已经创建好了,对于程序而言却还没有--还没有进行必要的初始化。进行完之前的两步之后 就是调用构造器了。构造器执行完之后就得到了你想好的对象。

    

         到此,对象的布局和对象的创建过程就结束了。对于应用程序的编程,了解这些就可以了。对于服务器编程,还远远不够。另外,对象的创建过程还不止这些,这就涉及到具体的GC了。这里先说下Java对象创建过程中的原子性保证。

         为了保证Java对象在创建的过程中的一致性,提供的方案有两个:1.对内存的分配采用同步机制--虚拟机采用的是CMS和失败重试的方法来保证内存分配的原子性。另一个方案是在Java堆中为每个线程预先分配一块线程私有的缓冲区,每个线程都在各自的缓冲区中分配对象,互不干扰!

        对象的内存定位

        对象的内存定位是指如何通多应用变量找到对象,有另种定位方法:1.使用句柄。就是把所有对象的地址都放一个一块内存区域中(这块区域称为对象的句柄池),每个对象在句柄池中有一个句柄(其中有对象实例数据的地址和对象对应的类的指针)。每次访问对象时,先在句柄池中找到对应的句柄,在由该句柄找到对应的对象。有点:提高程序的灵活性,在GC时对象的地址发生变化时只需要修改句柄即可。缺点:需要额外维护一个句柄池,需要两次定位操作。2.直接指针定位,即引用变量里存放着对象在Java堆中的地址。优点:减少了定位对象的时间开销,节省了内存空间(不再需要句柄池)。缺点:GC使对象的地址发生变化时需要改变引用变量的值。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值