【jvm学习笔记二】Java对象的创建过程

上文分析了Java类的加载过程,那么Java对象的创建过程是什么样呢?

public class Test {
    public static void main(String[] args) {
       Test data = new Test();
    }
}

以上为例,看下new关键字在底层是怎么实现的。
new关键字实现在InterpreterRuntime类中,如下:

IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index))
  Klass* k_oop = pool->klass_at(index, CHECK);
  instanceKlassHandle klass (THREAD, k_oop);

  // Make sure we are not instantiating an abstract klass
  klass->check_valid_for_instantiation(true, CHECK);

  // Make sure klass is initialized
  klass->initialize(CHECK);
  //分配实例
  oop obj = klass->allocate_instance(CHECK);
  thread->set_vm_result(obj);
IRT_END

主要分为四步:

  1. 从常量池pool中获取Klass,如果已加载并符号解析,则直接返回,否则根据情况符号解析或加载并符号解析;
  2. 检查是否是抽象类
  3. 初始化
  4. 分配实例创建对象

第一步的实现方法如下:

Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
  
  CPSlot entry = this_oop->slot_at(which);
  //如果要new的类已经加载并解析过(符号解析),则直接返回
  if (entry.is_resolved()) {
    assert(entry.get_klass()->is_klass(), "must be");
    // Already resolved - return entry.
    return entry.get_klass();
  }

  // 其他略

  Symbol* name = NULL;
  Handle       loader;
  {  MonitorLockerEx ml(this_oop->lock());

    if (this_oop->tag_at(which).is_unresolved_klass()) {
      if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
        in_error = true;
      } else {
        //从常量池中获取符合引用,类加载器
        do_resolve = true;
        name   = this_oop->unresolved_klass_at(which);
        loader = Handle(THREAD, this_oop->pool_holder()->class_loader());
      }
    }
  } // unlocking constantPool


 //错误处理略

  if (do_resolve) {
    // this_oop must be unlocked during resolve_or_fail
    oop protection_domain = this_oop->pool_holder()->protdomain();
    Handle h_prot (THREAD, protection_domain);
    //从SystemDictionary获取已加载的KlassOop,没有加载则加载
    Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD);
    KlassHandle k;
    if (!HAS_PENDING_EXCEPTION) {
      k = KlassHandle(THREAD, k_oop);
      // preserve the resolved klass.
      mirror_handle = Handle(THREAD, k_oop->java_mirror());
      // Do access check for klasses
      verify_constant_pool_resolve(this_oop, k, THREAD);
    }

    // 失败处理略
    }

    if (TraceClassResolution && !k()->oop_is_array()) {
        略

    } else {
      //符合引用变成直接引用,并更新到常量池中
      MonitorLockerEx ml(this_oop->lock());
      // Only updated constant pool - if it is resolved.
      do_resolve = this_oop->tag_at(which).is_unresolved_klass();
      if (do_resolve) {
        ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data();
        this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
        this_oop->klass_at_put(which, k());
      }
    }
  }

  entry = this_oop->resolved_klass_at(which);
  assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
  return entry.get_klass();
}

第三步初始化是重点:

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
  //获取初始化锁LC(每个类初始化锁唯一),没有则等待
  {
    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
    // 如果其他线程正在初始化,则释放LC并等待其他线程初始化完成,执行初始化过程不会被中断。
    // 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() && !this_oop->is_reentrant_initialization(self)) {
        wait = true;
      ol.waitUninterruptibly(CHECK);
    }

    // Step 3
    // 如果当前线程正在初始化,表明这是对初始化的递归请求(例:A的静态属性创建了B,B的静态属性又创建A),释放LC并返回
    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
    // 如果已经初始化完成,则释放LC并返回
    if (this_oop->is_initialized()) {
      DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_oop()), -1,wait);
      return;
    }

    // Step 5
    //如果初始化发生错误,则抛出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
    // 记录下当前线程正在初始化的Class对象
    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->should_be_initialized()) {
    super_klass->initialize(THREAD);

    if (HAS_PENDING_EXCEPTION) {
      Handle e(THREAD, PENDING_EXCEPTION);
      CLEAR_PENDING_EXCEPTION;
      {
        EXCEPTION_MARK;
        this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads
        CLEAR_PENDING_EXCEPTION;   // ignore any exception thrown, superclass initialization error is thrown below
      }
      DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait);
      THROW_OOP(e());
    }
  }

  // Recursively initialize any superinterfaces that declare default methods
  // Only need to recurse if has_default_methods which includes declaring and
  // inheriting default methods
  if (this_oop->has_default_methods()) {
    this_oop->initialize_super_interfaces(this_oop, CHECK);
  }
  
  // Step 8
  // 执行初始化方法,即clinit方法
  {
    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);
  }

  // Step 9
  // 初始化执行成功,则标记为完全初始化,并通知其他等待的线程,退出。
  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
    // 发生异常且异常不是error或它子类,则构建Exception对象抛出
    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
    }
    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);
}

最后创建对象

instanceOop InstanceKlass::allocate_instance(TRAPS) {
  bool has_finalizer_flag = has_finalizer(); // Query before possible GC
  int size = size_helper();  // Query before forming handle.

  KlassHandle h_k(THREAD, this);

  instanceOop i;
  //创建实例
  i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
  if (has_finalizer_flag && !RegisterFinalizersAtInit) {
    //注册finalizer
    i = register_finalizer(i, CHECK_NULL);
  }
  return i;
}

继续跟进obj_allocate:

oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
  //略
  //分配对象
  HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
  //对象初始化,根据是否使用偏向锁,设置对象头信息等操作。
  post_allocation_setup_obj(klass, obj, size);
  NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
  return (oop)obj;
}

继续跟进common_mem_allocate_noinit
···
HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {

// 略
HeapWord* result = NULL;
if (UseTLAB) {
//先尝试快速分配(tlab分配,eden区中线程专属区域),失败则再尝试从tlab中慢速分配,再失败会从eden区共享区域分配
result = allocate_from_tlab(klass, THREAD, size);
if (result != NULL) {
assert(!HAS_PENDING_EXCEPTION,
"Unexpected exception, will result in uninitialized storage");
return result;
}
}
//略
···
从tlab中快速分配失败后(如空间不够),会进入allocate_from_tlab_slow方法:
···
HeapWord* CollectedHeap::allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size) {

// 如果tlab空间大无法discard(这个阈值由TLABRefillWasteFraction比例控制),则记录并返回null(后续会从eden区共享区域分配)
if (thread->tlab().free() > thread->tlab().refill_waste_limit()) {
thread->tlab().record_slow_allocation(size);
return NULL;
}

// 重新分配一个tlab,为了减少内存碎片,此TLAB可能比上一个小
size_t new_tlab_size = thread->tlab().compute_size(size);

thread->tlab().clear_before_allocation();

if (new_tlab_size == 0) {
return NULL;
}

// Allocate a new TLAB...
HeapWord* obj = Universe::heap()->allocate_new_tlab(new_tlab_size);
if (obj == NULL) {
return NULL;
}
//略
return obj;
}
···
实例空间分配完成后,会进行一些初始化操作:

void CollectedHeap::init_obj(HeapWord* obj, size_t size) {
  assert(obj != NULL, "cannot initialize NULL object");
  const size_t hs = oopDesc::header_size();
  assert(size >= hs, "unexpected object size");
  //将对象空间除对象头外填0处理
  ((oop)obj)->set_klass_gap(0);
  //先将地址类型转换,然后把堆的字数转化为字节数,再对该段内存进行填值
  Copy::fill_to_aligned_words(obj + hs, size - hs);
}

对象的初始化,对象头的填充等操作在post_allocation_setup_obj方法中。

你可能感兴趣的:(【jvm学习笔记二】Java对象的创建过程)