第25章-类的初始化
这一章主要是讲类的初始化操作,后续类加载章节中也会用到这一章的知识,只不过,这里就讲,是因为虚拟在初始化过程中,需要对基础类,比如System/Thread等类进行初始化操作,所以就提前把这块内容先讲掉。
调用链
thread.cpp->create_vm()
// 这里只摘取了部分代码
initialize_class(vmSymbols::java_lang_String(), CHECK_0);// Initialize java_lang.System (needed before creating the thread)
initialize_class(vmSymbols::java_lang_System(), CHECK_0);
initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);
thread.cpp->initialize_class(Symbol* class_name, TRAPS)
static void initialize_class(Symbol* class_name, TRAPS) {Klass* klass = SystemDictionary::resolve_or_fail(class_name, true, CHECK);InstanceKlass::cast(klass)->initialize(CHECK);
}
instanceKlass.cpp->InstanceKlass::initialize
void InstanceKlass::initialize(TRAPS) {if (this->should_be_initialized()) {HandleMark hm(THREAD);instanceKlassHandle this_oop(THREAD, this);initialize_impl(this_oop, CHECK); // 真正的初始化操作在这里,看`章节25.1`// Note: at this point the class may be initialized// OR it may be in the state of being initialized// in case of recursive initialization!} else {assert(is_initialized(), "sanity check");}
}
25.1 类的初始化
25.1.1 instanceKlass.cpp
25.1.1.1 initialize_impl
函数中总共分成11个步骤来完成,这11个步骤在Java虚拟机规范文档中有描述,下面我们看看初始化时到底做了啥
void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {// Make sure klass is linked (verified) before initialization// A class could already be verified, since it has been reflected upon.this_oop->link_class(CHECK);DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_oop()), -1);bool wait = false;// refer to the JVM book page 47 for description of steps// Step 1{// 步骤1,初始化之前通过 ObjectLocker 对初始化操作加锁,防止多线程同步问题oop init_lock = this_oop->init_lock();ObjectLocker ol(init_lock, THREAD, init_lock != NULL);Thread *self = THREAD; // it's passed the current thread// Step 2// 步骤2,正在初始化的线程不是当前线程,那么释放获取到的锁,同时当前线程进入阻塞状态,等待其他线程完成初始化操作while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) {wait = true;ol.waitUninterruptibly(CHECK);}// Step 3// 步骤3,正在初始化的线程就是当前线程,那就表明这是对初始化的递归请求,释放锁if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) {DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_oop()), -1,wait);return;}// Step 4// 步骤4,已经初始化完成,那就不做什么,直接释放锁并返回if (this_oop->is_initialized()) {DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_oop()), -1,wait);return;}// Step 5// 步骤5,初始化过程出现错误,那就直接抛出异常 java_lang_NoClassDefFoundErrorif (this_oop->is_in_error_state()) {DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_oop()), -1,wait);ResourceMark rm(THREAD);const char* desc = "Could not initialize class ";const char* className = this_oop->external_name();size_t msglen = strlen(desc) + strlen(className) + 1;char* message = NEW_RESOURCE_ARRAY(char, msglen);if (NULL == message) {// Out of memory: can't create detailed error messageTHROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);} else {jio_snprintf(message, msglen, "%s%s", desc, className);THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);}}// Step 6// 步骤6,设置初始化状态为being_initialized,设置初始化的线程为当前线程this_oop->set_init_state(being_initialized);this_oop->set_init_thread(self);}// Step 7// 步骤7,如果当前初始化的类是类而不是接口,并且该类的父类还没有初始化,那就在父类上递归进行完整的初始化过程。如果父类初始化过程抛出异常,那么该类的初始化也要标为初始化错误状态,并通知所有正在等待的线程,然后抛出父类初始化抛出的异常。if (!this_oop->is_interface()) {Klass* super_klass = this_oop->super();if (super_klass != NULL && super_klass->should_be_initialized()) {super_klass->initialize(THREAD); // 父类初始化过程}if (!HAS_PENDING_EXCEPTION && this_oop->has_default_methods()) {this_oop->initialize_super_interfaces(this_oop, THREAD);}// If any exceptions, complete abruptly, throwing the same exception as above.if (HAS_PENDING_EXCEPTION) {Handle e(THREAD, PENDING_EXCEPTION);CLEAR_PENDING_EXCEPTION;{EXCEPTION_MARK;// Locks object, set state, and notify all waiting threadsthis_oop->set_initialization_state_and_notify(initialization_error, THREAD);CLEAR_PENDING_EXCEPTION;}DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait);THROW_OOP(e());}}// Step 8// 步骤8,做一些检查工作及性能数据处理后,就真正调用初始化函数,进行实际初始化工作{assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");JavaThread* jt = (JavaThread*)THREAD;DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_oop()), -1,wait);// Timer includes any side effects of class initialization (resolution,// etc), but not recursive entry into call_class_initializer().PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),ClassLoader::perf_class_init_selftime(),ClassLoader::perf_classes_inited(),jt->get_thread_stat()->perf_recursion_counts_addr(),jt->get_thread_stat()->perf_timers_addr(),PerfClassTraceTime::CLASS_CLINIT);this_oop->call_class_initializer(THREAD); // 调用类和接口的初始化函数,看`章节25.1.1.2`}// Step 9// 步骤9,初始化过程没有任务异常,说明已经完成初始化,设置类的状态为full_initialized并通知其他线程初始化已完成if (!HAS_PENDING_EXCEPTION) {this_oop->set_initialization_state_and_notify(fully_initialized, CHECK);{ ResourceMark rm(THREAD);debug_only(this_oop->vtable()->verify(tty, true);)}}else {// Step 10 and 11// 步骤10、11,初始化过中发生异常,则通过 set_initialization_state_and_notify 函数设置类的状态 initialization_error ,同时通知其他线程,并抛出异常Handle e(THREAD, PENDING_EXCEPTION);CLEAR_PENDING_EXCEPTION;// JVMTI has already reported the pending exception// JVMTI internal flag reset is needed in order to report ExceptionInInitializerErrorJvmtiExport::clear_detected_exception((JavaThread*)THREAD);{EXCEPTION_MARK;this_oop->set_initialization_state_and_notify(initialization_error, THREAD);CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below// JVMTI has already reported the pending exception// JVMTI internal flag reset is needed in order to report ExceptionInInitializerErrorJvmtiExport::clear_detected_exception((JavaThread*)THREAD);}DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_oop()), -1,wait);if (e->is_a(SystemDictionary::Error_klass())) {THROW_OOP(e());} else {JavaCallArguments args(e);THROW_ARG(vmSymbols::java_lang_ExceptionInInitializerError(),vmSymbols::throwable_void_signature(),&args);}}DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_oop()), -1,wait);// 至此,类的初始化工作完成。
}
25.1.1.2 call_class_initializer
void InstanceKlass::call_class_initializer(TRAPS) {instanceKlassHandle ik (THREAD, this);call_class_initializer_impl(ik, THREAD);
}// 从_methods数组中查询出 clinit 函数,并返回,_methods 数组内容来源于类加载和解析,这块内容会在类加载一章中讲,现在只要知道有这么一个数组存放该 klass/对象 的所有方法就行。这里也简单介绍下clinit,该方法是由编译器自动生成的,看`图25-1`
Method* InstanceKlass::class_initializer() {Method* clinit = find_method(vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());if (clinit != NULL && clinit->has_valid_initializer_flags()) {return clinit;}return NULL;
}void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {if (ReplayCompiles &&(ReplaySuppressInitializers == 1 ||ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) {// Hide the existence of the initializer for the purpose of replaying the compilereturn;}// clinit 方法的句柄methodHandle h_method(THREAD, this_oop->class_initializer());assert(!this_oop->is_initialized(), "we cannot initialize twice");if (TraceClassInitialization) {tty->print("%d Initializing ", call_class_initializer_impl_counter++);this_oop->name()->print_value();tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_oop());}if (h_method() != NULL) {JavaCallArguments args; // No argumentsJavaValue result(T_VOID);// JavaCalls::call 表示调用java 方法,这里就是调用 clinit 方法JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)}
}
图25-1 红色框框起来的就是编译器自动生成的方法