Hotspot源码解析-第十七章-虚拟机万物创建(一)

第十七章-虚拟机万物创建

17.1 硬编码偏移计算

主要是对预加载的系统类的一些static字段的偏移进行计算,因为在C/C++中,对象分配后是一串连续的内存空间,各字段内容无法像java那样直接属性名获取,只能通过内存偏移位置来获取,所以这里要计算偏移位置

17.1.1 javaClasses.cpp

17.1.1.1 JavaClasses::compute_hard_coded_offsets
void JavaClasses::compute_hard_coded_offsets() {
  const int x = heapOopSize; // 指针占用大小,我们这里只讲32位,所以占4字节
  // instanceOopDesc 把这个想像成指向java对象的句柄,句柄本身是一个C++对象,也要占用空间,所以这里先计算句柄占用的空间,Java对象中各字段的偏移位置,都是是相对这个header的大小来计算
  const int header = instanceOopDesc::base_offset_in_bytes();

  // Throwable Class,计算异常类中详细消息、异常原因、异常堆栈等字段的偏移
  java_lang_Throwable::backtrace_offset  = java_lang_Throwable::hc_backtrace_offset  * x + header;
  java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header;
  java_lang_Throwable::cause_offset      = java_lang_Throwable::hc_cause_offset      * x + header;
  java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
  java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset *  x;

  // java_lang_boxing_object
  java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset + header;
  java_lang_boxing_object::long_value_offset = align_size_up((java_lang_boxing_object::hc_value_offset + header), BytesPerLong);

  // java_lang_ref_Reference: 对应Java中Reference,计算这个类的各字段偏移
  java_lang_ref_Reference::referent_offset = java_lang_ref_Reference::hc_referent_offset * x + header;
  java_lang_ref_Reference::queue_offset = java_lang_ref_Reference::hc_queue_offset * x + header;
  java_lang_ref_Reference::next_offset  = java_lang_ref_Reference::hc_next_offset * x + header;
  java_lang_ref_Reference::discovered_offset  = java_lang_ref_Reference::hc_discovered_offset * x + header;
  java_lang_ref_Reference::static_lock_offset = java_lang_ref_Reference::hc_static_lock_offset *  x;
  java_lang_ref_Reference::static_pending_offset = java_lang_ref_Reference::hc_static_pending_offset * x;
  // Artificial fields for java_lang_ref_Reference
  // The first field is for the discovered field added in 1.4
  java_lang_ref_Reference::number_of_fake_oop_fields = 1;

   // 下面是一些其他类的字段偏移计算,参考上面的介绍就行,这里不一一介绍了,以下的类在Java中都有一一对应的类定义
   
  // java_lang_ref_SoftReference Class
  java_lang_ref_SoftReference::timestamp_offset = align_size_up((java_lang_ref_SoftReference::hc_timestamp_offset * x + header), BytesPerLong);
  // Don't multiply static fields because they are always in wordSize units
  java_lang_ref_SoftReference::static_clock_offset = java_lang_ref_SoftReference::hc_static_clock_offset * x;

  // java_lang_ClassLoader
  java_lang_ClassLoader::parent_offset = java_lang_ClassLoader::hc_parent_offset * x + header;

  // java_lang_System
  java_lang_System::static_in_offset  = java_lang_System::hc_static_in_offset  * x;
  java_lang_System::static_out_offset = java_lang_System::hc_static_out_offset * x;
  java_lang_System::static_err_offset = java_lang_System::hc_static_err_offset * x;
  java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x;

  // java_lang_StackTraceElement
  java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset  * x + header;
  java_lang_StackTraceElement::methodName_offset = java_lang_StackTraceElement::hc_methodName_offset * x + header;
  java_lang_StackTraceElement::fileName_offset   = java_lang_StackTraceElement::hc_fileName_offset   * x + header;
  java_lang_StackTraceElement::lineNumber_offset = java_lang_StackTraceElement::hc_lineNumber_offset * x + header;
  java_lang_AssertionStatusDirectives::classes_offset = java_lang_AssertionStatusDirectives::hc_classes_offset * x + header;
  java_lang_AssertionStatusDirectives::classEnabled_offset = java_lang_AssertionStatusDirectives::hc_classEnabled_offset * x + header;
  java_lang_AssertionStatusDirectives::packages_offset = java_lang_AssertionStatusDirectives::hc_packages_offset * x + header;
  java_lang_AssertionStatusDirectives::packageEnabled_offset = java_lang_AssertionStatusDirectives::hc_packageEnabled_offset * x + header;
  java_lang_AssertionStatusDirectives::deflt_offset = java_lang_AssertionStatusDirectives::hc_deflt_offset * x + header;

}
17.1.1.2 Universe::initialize_heap

这里才是真正Java堆空间的创建

jint Universe::initialize_heap() {
  // 下面是对使用的垃圾收集器的判断,为了讲解简单,这里只讲最简单的串行垃圾收集器,其他垃圾收集器可以作为读者扩展知识加以研究
  if (UseParallelGC) {
#if INCLUDE_ALL_GCS
    Universe::_collectedHeap = new ParallelScavengeHeap();
#else  // INCLUDE_ALL_GCS
    fatal("UseParallelGC not supported in this VM.");
#endif // INCLUDE_ALL_GCS

  } else if (UseG1GC) {
#if INCLUDE_ALL_GCS
    G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt();
    g1p->initialize_all();
    G1CollectedHeap* g1h = new G1CollectedHeap(g1p);
    Universe::_collectedHeap = g1h;
#else  // INCLUDE_ALL_GCS
    fatal("UseG1GC not supported in java kernel vm.");
#endif // INCLUDE_ALL_GCS

  } else {
    GenCollectorPolicy *gc_policy;
    // 古老的串行GC,这里是我们要讲的
    if (UseSerialGC) {
      // 创建标记清除策略对象,MarkSweepPolicy继承自分代收集策略类GenCollectorPolicy,看到分代是不是就熟悉了,就是所谓的老年代和新生代,这一步也没做啥,就是创建一个对象,并初始化对象的字段,字段详细先不介绍,等下用到再讲
      gc_policy = new MarkSweepPolicy();
    } else if (UseConcMarkSweepGC) {
#if INCLUDE_ALL_GCS
      if (UseAdaptiveSizePolicy) {
        gc_policy = new ASConcurrentMarkSweepPolicy();
      } else {
        gc_policy = new ConcurrentMarkSweepPolicy();
      }
#else  // INCLUDE_ALL_GCS
    fatal("UseConcMarkSweepGC not supported in this VM.");
#endif // INCLUDE_ALL_GCS
    } else { // default old generation
      gc_policy = new MarkSweepPolicy();
    }
    // GC策略初始化操作,详情见`章节17.2`
    gc_policy->initialize_all();
    // 通过GC策略,创建分代收集堆空间对象,详情见`章节17.3`
    Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
  }
  // 设置线程本地分配缓存的最大值
  ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size());
  // 针对Java堆空间进行初始化操作,详情见`章节17.4`
  jint status = Universe::heap()->initialize();
  if (status != JNI_OK) {
    return status;
  }
// 以下是64位机器实现,不做描述
#ifdef _LP64
  if (UseCompressedOops) {
    // Subtract a page because something can get allocated at heap base.
    // This also makes implicit null checking work, because the
    // memory+1 page below heap_base needs to cause a signal.
    // See needs_explicit_null_check.
    // Only set the heap base for compressed oops because it indicates
    // compressed oops for pstack code.
    if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) {
      // Can't reserve heap below 32Gb.
      // keep the Universe::narrow_oop_base() set in Universe::reserve_heap()
      Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
#ifdef AIX
      // There is no protected page before the heap. This assures all oops
      // are decoded so that NULL is preserved, so this page will not be accessed.
      Universe::set_narrow_oop_use_implicit_null_checks(false);
#endif
    } else {
      Universe::set_narrow_oop_base(0);
#ifdef _WIN64
      if (!Universe::narrow_oop_use_implicit_null_checks()) {
        // Don't need guard page for implicit checks in indexed addressing
        // mode with zero based Compressed Oops.
        Universe::set_narrow_oop_use_implicit_null_checks(true);
      }
#endif //  _WIN64
      if((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
        // Can't reserve heap below 4Gb.
        Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
      } else {
        Universe::set_narrow_oop_shift(0);
      }
    }

    Universe::set_narrow_ptrs_base(Universe::narrow_oop_base());

    if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
      Universe::print_compressed_oops_mode(tty);
    }
  }
  // Universe::narrow_oop_base() is one page below the heap.
  assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() -
         os::vm_page_size()) ||
         Universe::narrow_oop_base() == NULL, "invalid value");
  assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes ||
         Universe::narrow_oop_shift() == 0, "invalid value");
#endif

  // We will never reach the CATCH below since Exceptions::_throw will cause
  // the VM to exit if an exception is thrown during initialization

  if (UseTLAB) {
    assert(Universe::heap()->supports_tlab_allocation(),
           "Should support thread-local allocation buffers");
    ThreadLocalAllocBuffer::startup_initialization();
  }
  return JNI_OK;
}

你可能感兴趣的:(Java虚拟机,java)