专注虚拟机与编译器研究

第7.6篇-类的初始化

对类进行初始化时,通常会调用如下方法:

void InstanceKlass::initialize(TRAPS) {
  if (this->should_be_initialized()) {
    HandleMark hm(THREAD);
    instanceKlassHandle this_oop(THREAD, this);
    initialize_impl(this_oop, CHECK);
    // 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");
  }
}

调用InstanceKlass::initialize_impl()方法对类进行初始化。这个方法的源代码位置在oops/instanceKlass.cpp。在对类进行初始化之前必须保证类已经完成连接,I在连接完成后要进行类的初始化。initialize_impl()方法的实现如下:

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);

  bool wait = false;

  // refer to the JVM book page 47 for description of steps
  // step 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:如果当前instanceKlassHandle正在被初始化,且初始化线程不是当前线程,
    // 则执行ol.waitUninterruptibly(CHECK),等待其他线程初始化完成后通知。
    // If we were to use wait() instead of waitInterruptibly() then
    // we might end up throwing IE from link/symbol resolution sites
    // that aren't expected to throw.  This would wreak havoc.  See 6320309.
    while(
 	this_oop->is_being_initialized() &&          // 类正在进行初始化(being_initialized状态)
	!this_oop->is_reentrant_initialization(self) // 执行初始化的线程不是当前的线程
    ){
        wait = true;
        ol.waitUninterruptibly(CHECK);
    }

    // step 3:当前类正在被当前线程正在被初始化。例如如果X类有静态变量指向new Y类实例,Y类中又有静态变量指向new X类实例,
    // 这样外部在调用X时需要初始化X类,初始化过程中又要触发Y类的初始化,而Y类初始化又再次触发X类的初始化
    if (
        this_oop->is_being_initialized() &&         // 类正在进行初始化(being_initialized状态)
	this_oop->is_reentrant_initialization(self) // 执行初始化的线程的就是当前线程
    ){
       return;
    }

    // step 4:类已经初始化完成(fully_initialized状态)
    if (this_oop->is_initialized()) {
       return;
    }

    // step 5:类的初始化出错(initialization_error状态),则抛出NoClassDefFoundError异常
    if (this_oop->is_in_error_state()) {
      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:设置类的初始化状态为being_initialized,设置初始化的线程为当前线程
    this_oop->set_init_state(being_initialized);
    this_oop->set_init_thread(self);
  }

  // step 7:如果当前初始化的不是接口、父类不为空并且父类未初始化,则初始化其父类
  Klass* super_klass = this_oop->super();
  if (
	  super_klass != NULL &&
	  !this_oop->is_interface() &&
	  // 也就是判断super_klass的状态是否为fully_initialized,
	  // 如果是,should_be_initialized()方法将返回true
	  super_klass->should_be_initialized()
  ){
    super_klass->initialize(THREAD);
    // ...
  }

  if (this_oop->has_default_methods()) {
    // Step 7.5: 初始化有默认方法的接口
    for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
      Klass*          iface = this_oop->local_interfaces()->at(i);
      InstanceKlass*  ik = InstanceKlass::cast(iface);
      if (ik->has_default_methods() && ik->should_be_initialized()) {
          ik->initialize(THREAD);
          // ...
      }
    }
  }

  // Step 8
  // 执行类或接口的初始化方法<clinit>
  {
    this_oop->call_class_initializer(THREAD); // 调用类或接口的<clinit>方法
  }

  // Step 9
  // 如果初始化过程没有异常,说明已经完成初始化,设置类的状态为full_initialized并通知其他线程初始化已经完成。
  if (!HAS_PENDING_EXCEPTION) {
    this_oop->set_initialization_state_and_notify(fully_initialized, CHECK);
  }
  else {
    // Step 10 and 11
    // 如果初始化过程发生异常,则通过set_initialization_state_and_notify()方法设置类的
    // 状态为initialization_error并通知其他线程,然后抛出错误或异常
    Handle e(THREAD, PENDING_EXCEPTION);
    CLEAR_PENDING_EXCEPTION;
    {
      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
    }
    // ...
  }
}

方法执行的逻辑清晰的展示了类初始化所需要做的事情。在类初始化过程中会涉及到对类状态的判断,之前介绍过,使用InstanceKlass::_init_state来表示类的状态,取值如下:

enum ClassState {
    allocated,            // allocated (but not yet linked)
    loaded,               // loaded and inserted in class hierarchy (but not linked yet)
    linked,               // successfully linked/verified (but not initialized yet) 
    being_initialized,    // currently running class initializer
    fully_initialized,    // initialized (successfull final state)
    initialization_error  // error happened during initialization
};

如果当前类正在被初始化,那么状态为being_initialized;如果当前类已经完成初始化,则状态为fully_initialized;如果当前类初始化出错,则状态为initialization_error。 

在类初始化过程中,最重要的就是调用类的<clinit>方法了,大家如果不明白<clinit>方法的作用及产生的过程,可以参考本作者写的另外一本书《深入解析Java编译器:源码剖析与实例详解》,这本书将会详细介绍这个方法的来龙去脉。调用InstanceKlass::call_class_initializer()函数来执行<clinit>方法,函数的实现如下: 

void InstanceKlass::call_class_initializer(TRAPS) {
  instanceKlassHandle ik (THREAD, this);
  call_class_initializer_impl(ik, THREAD);
}

void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {
  // ...

  methodHandle h_method(THREAD, this_oop->class_initializer());
  assert(!this_oop->is_initialized(), "we cannot initialize twice");

  if (h_method() != NULL) {
     JavaCallArguments  args; // No arguments
     JavaValue          result(T_VOID);
     JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
  }
}

最终通过调用JavaCalls::call()函数来完成Java方法的调用,这个函数的实现非常重要,在前面也多次接触过这个函数,不过目前还没有介绍相关的执行过程,在介绍方法执行引擎时会详细介绍。  

 

posted on 2020-08-13 15:49  鸠摩(马智)  阅读(914)  评论(0编辑  收藏  举报

导航