JVM(Java Virtual Machine)对象创建过程

204 阅读2分钟

对象创建详解

  1. 当虚拟机遇到字节码指令new时,判断指令是否能在常量池中定位到一个类的符号引用,并检查这个类是否被加载,解析和初始化,如果没有则执行类的初始化。

  2. 为对象分配内存 (对象所占用内存大小在类加载完成后即可确定)

    2.1)、 内存分配的俩种方式:

    2.1.1)、指针碰撞: 是指内存是整齐有序情况下
    
    2.1.2)、空闲列表: 内存存储不规整情况下
    
    2.1.3)、内存是否整齐是由垃圾回收器是否带有空间压缩整理来决定的。
    
    2.1.4) 、Serial、ParNew 等垃圾回收器带空间压缩整理
    
    2.1.5) 、CMS这种基于清除算法垃圾回收器,只能采用空闲列表分配内存
    

    2.2)、对象在虚拟机中频繁创建,在并发场景下也是不安全的。 (可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况) 以上问题有两种解决方式。

    2.2.1 、同步锁:JVM采用CAS方式失败重试方式来保证原子性。
    
    2.2.2 、本地线程分配缓存区(TLAB):按照不同线程划分不同空间中进行,每个线程在java堆中预先分配一块小内存,称为本地线程分配缓存区,那个线程需要分配就在对应的缓存区中分配,如果本地缓存区使用完了,分配新的缓存区在使用同步锁方式。是否使用TLAB,可通过配置参数决定(-XX:+/-useTALB)。以空间换取时间方式,默认大小是512k。
    
  3. 对象的内存布局

堆在内存中存储布局分为三部分:对象头、实例数据、对齐填充

对象头:

第一种:自身的运行时数据(哈希吗、GC分代年龄、锁标志状态、线程持有锁...)

第二种:类型指针(对象指向它的类型元数据,虚拟机通过指针确定该对象是那个类的实例)

实例数据:

存储有效数据(代码所定义的各种字段内从,父类继承或者是子类中定义的都保存下来)

对齐填充:

虚拟机要求对象起始地址必须是8字节的整数倍,因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

4.以上完成后从虚拟机角度来看一个新对象已经产生,如果从应用程序来看对象才开始构造函数。