Java虚拟机中对象的创建过程

JVM

步骤一

当java虚拟机遇到new指令的时候,首先检查这个指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载链接初始化了,如果没有,则先执行相应的类的加载过程。

步骤二

类加载检查通过后,为新生的对象分配内存,对象的内存在类加载完成后就完全确定了。为对象分配内存就是把一块确定大小的内存从java堆中划分出来。

为对象分配内存两个注意的问题:

如何划分可用空间

根据java堆中的内存是否规整,有两种方式进行划分:

  • 内存规整 指针碰撞
  • 内存不规整 空闲列表

指针碰撞:如果内存是规整的,所有的用过的内存都放在一边,所有空闲的内存都放在一边,中间放着一个指针作为分界点的指示器,分配内存的时候,把指针向空闲的内存那边移动跟对象的大小相等的距离。

空闲列表:内存是不规整的,虚拟机维护一个列表,列表中记录着那些内存是空闲的那些内存在被占用,然后分配内存的时候,找出一块足够大的空间分配给对象使用,并跟新列表上的内容。

使用哪种方式是有内存是否规整决定的,而内存是否规整,是由所使用的垃圾收集器是否带有压缩整理功能决定的。

内存分配的同步问题

对象的创建在虚拟机种非常的频繁,即使是修改一个指针,在并发访问下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针进行内存分配。

解决方法有两种

  • 对分配内存空间的动作进行同步处理
  • 把内存分配的动作按照线程划分在不同的空间上进行,给每个线程在java堆上预先分配一小块内存,称为本地线程分配缓冲。那个线程需要分配内存,就在那个线程的TLAB上进行内存分配,只有当先前线程的TLAB空间用完之后,分配新的TLAB空间的时候才进行同步处理。是否使用TLAB通过设置jvm的参数来决定。

步骤三

内存分配完成,初始化所有的内存空间为0,如果使用TLAB,这一步骤可以在TLAB分配时完成。

步骤四

对对象进行必要的设置,例如对象是哪个类的实例,如何才能找到类的元数据信息,对象的hash码,对象的GC分代年龄等信息,这些信息都放在对象头里面。

步骤五

前四个步骤执行完后,在虚拟机的角度对象已经创建完了,但是在java的角度,对象创建才刚开始,接下来执行init方法,来将初始化对象的字段。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器