JVM中Java对象的创建过程 — JVM系列(二)

前言

Java的中的以下几种对象,在内存中存放位置:

  • new出来的普通对象
  • 克隆出来的对象
  • 反序列化出来的对象
  • Class对象
  • 数组

前三种是存放在Java堆中的,后两种是存放在方法区中的。

以下重点描述的是Java堆中创建一个对象的流程

第一步:检查类是否加载过

第一步:检查对象所属的类是否才运行时常量池中定位到了一个类的符号引用,并且这个类是否已被加载,解析和初始化过,如果没有,需要先进行加载,解析和初始化。

第二步:给对象分配内存空间

第二步:为我们的新生对象分配内存,对象所需内存大小在类加载完成后便可完全确定。有以下两种分配方法:

  1. 指针碰撞:Java堆中的内存是规整的,一边是使用完的内存,一边是没使用的内存,临界处用一个指针来标记,只要将指针向空闲的那边移动对象所需的内存大小即可完成对象内存的分配。
  2. 空闲列表:Java堆中的内存不是规整的,虚拟机就必须维护一个列表,记录哪些内存是可用的,在给对象分配内存的时候,找到一块足够的内存分给对象,并更新这个列表即可,这个列表就是空闲列表。

Java堆中的内存是否规整,是由垃圾收集器是否带有压缩整理功能决定的。

serial、ParNew等带有Compact过程的收集器,系统采用的分配算法是指针碰撞。

而采用CMS这种基于Mark-Sweep算法的收集器,系统采用的是空闲列表分配内存空间的方法。

在创建对象的过程中,为了防止并发创建对象的过程中对内存修改可能导致的线程安全问题有两种解决方式:

  1. 虚拟机采用CAS配上失败重试的方式保证更新操作的原子性。
  2. 把内存分配的操作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲TLAB,哪个线程要分配内存,就在那个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定,虚拟机是否采用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

第三步:给分配的空间初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化零值,其中不包括对象头。如果采用TLAB,这一工作可能提前至TLAB分配时进行。

对象头中,存有:

  • 这个对象是哪个类的实例
  • 如何能找到类的元数据信息
  • 对象的哈希码
  • 对象的GC的分代命令
  • 是否采用偏向锁等

第四步:执行对象的init方法初始化

把对象按照程序员的意愿初始化后,这样一个真正可用的对象才算完全产生出来。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章