第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_NoClassDefFoundError
if (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 message
THROW_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 threads
this_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 ExceptionInInitializerError
JvmtiExport::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 ExceptionInInitializerError
JvmtiExport::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 compile
return;
}
// 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 arguments
JavaValue result(T_VOID);
// JavaCalls::call 表示调用java 方法,这里就是调用 clinit 方法
JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
}
}
图25-1 红色框框起来的就是编译器自动生成的方法