The creation process of Java objects in JVM source code analysis

This article will conduct an in-depth analysis of the Java object creation process based on the HotSpot implementation.

Define two simple classes AAA and BBB


View the compiled bytecode through ``javap -c AAA````, as follows:


The new keyword in Java corresponds to the new instruction in jvm, which is defined in the InterpreterRuntime class and is implemented as follows:


The implementation process of the new instruction:
1. The pool is the constant pool of AAA. At this time, the class of AAA has been loaded into the virtual machine. #2The symbol after the new instruction that represents the fully qualified name of the BBB class refers to the location of the constant pool;
2. Method pool->klass_atResponsible for returning the klassOop object corresponding to the BBB, implemented as follows:


If the data in the specified position (#2) in the constant pool is already an oop type, it means that the class of BBB has been loaded and parsed, then (klassOop)entry.get_oop()return klassOop directly; otherwise, it means that the first time to use BBB, you need to parse the symbolic reference of BBB, and Load the class class of BBB, generate the corresponding instanceKlass object, and update the symbol reference of the corresponding position in the constant pool;
3. It klass->check_valid_for_instantiationcan prevent the abstract class from being instantiated;
4. The klass->initializeimplementation is as follows:


If the instanceKlass object of BBB has been initialized, it will return directly; otherwise, it will initialize_implbe initialized by the method. The whole initialization algorithm is divided into 11 steps, and the specific implementation is as follows:

step1

Lock before initialization by ObjectLocker to prevent concurrent initialization of multiple threads.

step2

If the current instanceKlass is in the being_initialized state and is being initialized by other threads, the execution ol.waitUninterruptiblywaits for other threads to complete the notification.

step3

如果当前instanceKlass处于being_initialized状态,且被当前线程初始化,则直接返回。
其实对于这个step的处理我有疑问,什么情况会走到这一步?经过RednaxelaFX大大提点,如下情况会执行step3:
例如A类有静态变量指向一个new B类实例,B类里又有静态变量指向new A类实例,这样外部用A时要初始化A类,初始化过程中又要触发B类初始化,B类初始化又再次触发A类初始化。

step4

如果当前instanceKlass处于fully_initialized状态,说明已经初始化完成,则直接返回;

step5

如果当前instanceKlass处于initialization_error状态,说明初始化失败了,抛出异常。

step6

设置当前instanceKlass的状态为 being_initialized;设置初始化线程为当前线程。


如果当前instanceKlass不是接口类型,并且父类不为空,且还未初始化,则执行父类的初始化。

step8

通过this_oop->call_class_initializer方法执行静态块代码,实现如下:


this_oop->class_initializer()可以获取静态代码块入口,最终通过JavaCalls::call执行代码块逻辑,再下一层就是具体操作系统的实现了。

step9

如果初始化过程没有异常,说明instanceKlass对象已经初始完成,则设置当前instanceKlass的状态为 fully_initialized,最后通知其它线程初始化已经完成;否则执行step10 and 11。

step10 and 11

如果初始化发生异常,则设置当前instanceKlass的状态为 initialization_error,并通知其它线程初始化发生异常。

5、如果instanceKlass初始化完成,klass->allocate_instance会在堆内存创建instanceOopDesc对象,即类的实例化;

instanceOopDesc

当在Java中new一个对象时,本质是在堆内存创建一个instanceOopDesc对象。


instanceOopDesc在实现上继承自oopDesc,其中oopDesc定义如下:


当然,这只是 oopDesc的部分实现,oopDesc包含两个数据成员:_mark 和 _metadata。
1、_mark是markOop类型对象,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,占用内存大小与虚拟机位长一致,更具体的实现可以阅读 《java对象头的HotSpot实现分析》
2、_metadata是一个联合体,其中wideKlassOop和narrowOop都是指向InstanceKlass对象的指针,wide版是普通指针,narrow版是压缩类指针(compressed Class pointer)

instanceOopDesc对象的创建过程


instanceOopDesc对象通过instanceKlass::allocate_instance进行创建,实现过程如下:
1、has_finalizer判断当前类是否包含不为空的finalize方法;
2、size_helper确定创建当前对象需要分配多大内存;
3、CollectedHeap::obj_allocate从堆中申请指定大小的内存,并创建instanceOopDesc对象,实现如下:


4、如果当前类重写了finalize方法,且非空,需要把生成的对象封装成Finalizer对象并添加到 Finalizer链表中,对象被GC时,如果是Finalizer对象,会将对象赋值到pending对象。Reference Handler线程会将pending对象push到queue中,Finalizer线程poll到对象,先删除掉Finalizer链表中对应的对象,然后再执行对象的finalize方法;

资料来源:http://www.jianshu.com/p/0009aaac16ed

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324131876&siteId=291194637