对象的创建过程
java是一门面向对象的编程语言,在程序运行过程中无时无刻都有对象被创建。对于语言层面来说,创建对象通过new关键字就可以实现,但在JVM层面上伴随着以下的复杂过程:
1、检查
到虚拟机遇到一条new指令时,首先将去检查这个指令的参数(类的符号引用)能否在常量池中定位到一个类,并检查这个符号引用代表的类是否已被加载解析和初始化,如果没有则先执行类加载过程。
2、分配内存
检查通过后将为新生对象分配内存,对象所需的内存大小在类加载完成后便已确定,为对象分配空间的过程相对于把一块确定大小的内存从java堆中划分出来。那么按照内存是否规整分为两种方式:指针碰撞、空闲列表。
指针碰撞(Bump the Pointer):内存是规整的,使用的内存和空闲的内存各在一边,中间是一个指针作为分界点指示,那么分配空间的过程就是按对象所需内存将这个指针往空闲区域移动一段距离。
空闲列表(Free List):内存不是规整的,使用的内存和空闲的内存交错,那么虚拟机就得维护一个记录着内存块是否可用的列表,分配空间的过程就是在列表中找到一块足够大的空间划分给该实例,并更新列表上的记录。
分配空间时的并发解决:因为创建对象在虚拟机中非常频繁,在并发操作的情况下会出现线程安全问题(1线程在给对象A分配内存,指针还没来得及修改,此时2线程又在用原来的指针给对象B分配内存),解决方案有两种:分配内存做同步处理(采用CAS配上失败重试的方法保证分配内存操作的原子性),把内存分配按不同线程划分在不同空间进行。
本地线程分配缓冲(Thread Local Allocation Buffer,TLAB):即预先为每个线程在java堆中分配一小块内存,分配内存就在当前线程的TLAB中进行,当TLAB用完分配新的TLAB时才需要同步锁定。可通过-XX:+/-UseTLAB参数来设定虚拟机使用TLAB。
3、初始化
将分配到的内存空间都初始化为零值,如果使用了TLAB,初始化的步骤提至TLAB分配时进行。此过程保证了对象的实例变量不设置初始值也可以正常使用。
4、设置参数
包括对象属于哪个类、对象的哈希码、GC分代年龄、锁的信息等设置并存储在对象头中(具体参看JVM系列之对象的内存布局)。
5、构造函数
执行自定义的(或是自动生成的)构造函数<init>方法进行对象初始化。