对象的创建

对象的创建

当虚拟机遇到一条 字节码new指令时,

  1. 检查这个指令的参数是否在常量池中定位到一个类的符号引用;

  2. 并检查这个符号引用代表的类是否已被 加载、解析、初始化过,如过没有,必须执行相应的类加载过程;

  3. 在类加载检查通过之后,虚拟机将会为新生对象分配内存

    • 对象所需的内存在类加载后就可以完全确定;

    • 为对象分配内存其实就是在堆上划分出一个确定大小的内存

    • 有两种分配内存的方式:

      • “指针碰撞”:堆内存规整,垃圾收集器带有空间压缩整理能力(Serial、ParNew)

      • “空闲列表“:堆内存不规整,垃圾收集器不带空间压缩整理能力(CMS 基于”清除swap“算法)

    虚拟机创建对象内存分配时的线程安全问题的解决:

    • 对分配内存空间的动作进行同步处理。实际上,虚拟机采用CAS配上失败重试的方式保证更新操作的原子性

    • 把内存分配的动作按照线程划分到不同的空间中进行。即每个线程在java堆中预先一小块内存,称为本地线程分配缓存(Thread Local Allocation Buffer,TLAB)分配内存时在该线程的本地缓冲区分配,只有本地缓冲区用完了,分配新的缓冲区时才需要同步锁定。虚拟机是否使用TLAB,可以通过 -XX:+/-UseTLAB参数来设定。

  4. 内存分配完成后,虚拟机必须将分配到的内存空间(不包括对象头)都初始化为零值。如果使用了TLAB,这个步骤可以提前至TLAB分配时顺便进行。这个步骤保证了对象的实例字段可以不赋初值就直接使用。

  5. 接下来,虚拟机需要对对象进行必要的设置,例如,这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法是时才计算)、对象的GC分代年龄等信息。这些信息存放在对象头(Object Header)中。

  6. 上述工作完成之后,Class文件的<init>()方法还没有执行,所有的字段都是默认值。new之后会接着执行<init>()方法按照程序员的意愿对对象进行初始化,这样一个真正可用的对象才算被构造出来

总结:new一个对象包括:类是否加载、为对象分配内存、并发处理、内存空间初始化、对象设置、<init>()等步骤

posted @ 2021-03-09 15:16  keepkeep  阅读(35)  评论(0编辑  收藏  举报