摘要:Java 虚拟机系列是博主在学习周志明先生的书籍所做的理解性笔记,方便自己复习,如果能够帮到他人十分荣幸。

对象的创建:

  1. 当虚拟机遇到一条new指令的时候,首先查看这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用是否被加载,解析和引用过。如果没有,那必须先执行相应的类加载过程。
  2. 在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存大小在类加载完成后便可以确定,为对象分配内存是把一块确定大小的内存从 Java堆中划分出来。存在两种方式;

         (1)如果java堆内存是绝对规整的,将未使用的内存放在一边,已经使用的放在另外一边,中间放置一个指针做为分界点指示器,那分配内存就是将指针指示器向未使用内存移动对象所需大小的内存空间。这种分配方式叫做“指针碰撞”。

         (2)如果java堆中的内存并不是规整的,已经使用的和未使用的内存相互交错,那就没有办法使用“指针碰撞”了,虚拟机就必须维护一个表,标记哪些是使用过的内存,哪些没有使用过,在支配的时候从列表中找到一块足够大的空间划分给分配对象实例,并且更新列表上的记录,这种方式叫做“空闲列表”。

           至于说选择哪种分配方式由Java堆是否完整来决定,而java堆是否完整又由所采用的垃圾回收收集器是否带有压缩整理功能决定。

     3.除如何划分可用空间以外,还有一个需要考虑的因素是对象创建在虚拟机中是非常频繁的,即使是一个修改指针所指向的问题,在并发的情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没有来得及修改,对象B又同时使用了原来的指针(应该分配给A)来分配内存的情况。这时我们为了保证操作不受打扰,使用更新操作的原子性(要做不做,要么全做)。

      当A在分配对象内存和指针修改的时候,并发情况的B则处于等待的状态,等A分配结束,B再进行分配,保证原子性。

    4.内存分配之后,虚拟机需要将分配到内存空间都初始为零,这一操作可以保证对象的实例字段在java代码中可以不被赋值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

    5.接下来,虚拟机要对对象进行必要的设计,例如这个对象是哪个类的实例,如何才能找到类的元数据信息,对象的哈希吗,对象的GC分代年龄等信息。

    6.上面的工作都完成以后,从虚拟机的角度来看,一个新的对象已经产生了,但从java的角度来看,对象创建才刚刚开始---<init>方法还没有执行,所有的字段都还为零。所以,一般来说,执行new指令之后会执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正的对象才算完全产生出来。