——Java作为纯面向对象的语言,运行过程无时无刻都有对象被创建。在语言层面上,创建对象(克隆、反序列化)通常仅仅体现为new关键字,而虚拟机中实际创建过程则更为复杂。

 

深入JVM 对象的创建

 

 

  • 虚拟机遇到一条new指令后,首先检查这个指令的参数是否能在常量池种定位到这个类的符号引用,并且检查这个符号引用代表的类是否被类加载、解析、和初始化,否则,必须先进行相应的类加载过程。
  • 类加载检查完后,紧接着虚拟机为新对象分配内存。对象所需的内存的大小在类加载后便可完全确定,为对象分配内存等同于把一块确定大小的内存从堆中划分出来。
  • 假设堆区域是规整的,所有使用过的内存放在一边,空闲的内存放在另一侧,中间的分界线由由指针指示,那么分配内存仅仅将指针向右移动与对象大小相等的距离。这种方式称为指针碰撞。
  • 如果Java堆的内存不是规整的,即已使用空间和未使用空间相互交错,那一般的做法是维护空间列表,记录下空间块的信息,分配对象内存工作是从空闲列表中寻找一块合适区域。
  • 除划分可用空间外,还需要考虑都对象创建在虚拟机是非常频繁的行为,即使修改指针的位置,如果在并发情况下不是线程安全的,可能出现为对象A分配内存,指针还没有修改,对象B又使用原先指针分配内存。
  • 通常解决方法是,一对分配内存的动作进行同步控制,采用CAS和失败重试的方式保证操作的原子性;另一种做法是把内存分配动作按照线程不同在不同的空间中进行,即每个线程在Java堆中预先分配一定大小空间,称为本地线程分配缓冲(Thread Local Allocation Buffer TLAB) ,线程在各自的TLAB进行
  • 内存分配完后,虚拟机将分配到的内存区域初始化为0 如果使用TLAB,这一工作提前至TLAB分配时进行。这一步操作保证对象实例字段在Java代码中可以不赋值就使用(默认值)
  • 接下来,虚拟机需要对对象进行必要的设置,例如对象从属于哪个类,如何找到类的元信息,对象的哈希码,这些信息存放在对象的对象头中(object header) 
  • 所有工作完成后,从虚拟机角度,完成了对象的产生,但从Java程序角度,对象创建才刚刚开始 init初始化方法还没有执行,所有字段还是零值,而init过程则按照编程的意愿进行初始化,至此,一个对象算真正产生

 

 

 

相关文章: