Java堆中对象建立、布局、访问全过程

1.建立对象

    建立对象一般仅仅是一个new关键词而已。程序员

1.1类加载检查

    虚拟机在建立对象以前须要先判断是否已经被加载,经过检查这个指令的参数是否能在常量池中定位到一个类的符号引用,而且检查这个符号引用表明的类是否已被加载、解析和初始化过。若是没有,那必须先执行相应的类的加载过程。算法

1.2为对象分配内存空间

    对象所需内存的大小在类加载完成后便彻底肯定,为对象分配空间的任务等同于把一块肯定大小的内存从Java堆中划分出来。缓存

1.2.1内存分配方式

    根据Java堆中的内存是否规整有两种内存的分配方式指针碰撞方式和空闲列表方式,Java堆是否规整由所采用的垃圾收集器是否带有压缩整理功能决定。安全

  • 指针碰撞(Bump the pointer):Java堆中的内存是规整的,全部用过的内存都放在一边,空闲的内存放在另外一边,中间放着一个指针做为分界点的指示器,分配内存也就是把指针向空闲空间那边移动一段与内存大小相等的距离。例如:Serial、ParNew等收集器。
  • 空闲列表(Free List):Java堆中的内存不是规整的,已使用的内存和空闲的内存相互交错,就没有办法简单的进行指针碰撞了。虚拟机必须维护一张列表,记录哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。例如:
    CMS这种基于Mark-Sweep算法的收集器。

1.2.2内存分配时的并发问题

    对象在虚拟机中建立时很是频繁的行为,即便是仅仅修改一个指针指向的位置,在并发状况下也并非线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的状况。解决这个问题有两种方案,一种是同步处理另外一种是本地线程分配缓存。并发

  • 同步处理:对分配内存空间的动做进行同步处理——实际上虚拟机采用CAS配上失败重试的方式保证更新操做的原子性。
  • 本地线程缓冲(TLAB):把内存分配的动做按照线程划分为在不一样的空间之中进行,即每一个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。哪一个线程要分配内存,就在哪一个线程的TLAB上分配。只有TLAB用完并分配新的TLAB时,才须要同步锁定。虚拟机是否使用TLAB,能够经过-XX:+/UserTLAB参数来设置。

1.3内存空间初始化

    虚拟机将分配到的内存空间都初始化为零值(不包括对象头),若是使用了TLAB,这一工做过程也能够提早至TLAB分配时进行。内存空间初始化保证了对象的实例字段在Java代码中能够不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。 spa

1.4设置对象

    虚拟机对对象进行必要的设置,例如这个对象是哪一个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。线程

1.5执行<init>方法

    在上面的工做都完成以后,从虚拟机的角度看,一个新的对象已经产生了。可是从Java程序的角度看,对象的建立才刚刚开始<init>方法尚未执行,全部的字段都仍是零。因此,通常来讲(由字节码中是否跟随invokespecial指令所决定),执行new指令以后会接着执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算产生出来。指针

相关文章
相关标签/搜索