Hotspot 内存管理之Universe 源码解析

     目录

1、定义

2、LatestMethodCache / NarrowPtrStruct

3、universe_init

4、universe2_init

5、universe_post_init

6、initialize_basic_type_mirrors

7、reserve_heap

8、oops_do


《Hotspot Java对象创建和TLAB源码解析》讲解Java对象创建和分配TLAB时,在《Hotspot 内存管理之MemoryService 源码解析》讲解MemoryService的set_universe_heap方法的调用时都频繁碰到Universe类,本篇博客就详细探讨Universe类的初始化和对外提供的接口。

1、定义

     Universe的定义位于hotspot src/shared/vm/memory/universe.hpp中,Universe类用来保存JVM中重要的系统类及其实例,如基础类型数组的Klass,用来提供对分配Java对象的CollectedHeap的访问入口,提供多种对象分配的方法。Universe定义的属性和对外提供的方法都是static的,除预先初始化好的重要的Klass或者oop外,关键的属性如下:

  •  LatestMethodCache* _finalizer_register_cache; //对应java_lang_ref_Finalizer类的register(Object finalizee)方法,该类是java_lang_ref包级私有的
  •  LatestMethodCache* _loader_addClass_cache;    //对应sun_reflect_DelegatingClassLoader类的addClass方法,DelegatingClassLoader是sun_reflect_ClassDefiner中定义的,包级访问,直接继承自java.lang.ClassLoader类
  •  LatestMethodCache* _pd_implies_cache;         //对应java_security_ProtectionDomain类的impliesCreateAccessControlContext方法
  •  LatestMethodCache* _throw_illegal_access_error_cache; //对应 Unsafe类的throwIllegalAccessError() 方法
  • CollectedHeap* _collectedHeap;  //负责Java对象分配的CollectedHeap引用
  • intptr_t _non_oop_bits; //用来标识某块内存不是一个合法的oop,在oop遍历时使用
  • NarrowPtrStruct _narrow_oop;//开启UseCompressedOops时,保存用来记录计算真实oop地址的base地址等属性
  • NarrowPtrStruct _narrow_klass; //开启UseCompressedClassPointers时,保存用来记录计算真实klass地址的base地址等属性
  • address _narrow_ptrs_base; //使用narrow_ptrs时的基地址
  • int  _base_vtable_size; //Klass中虚函数表占用内存的最小值,实际就是Object类Klass的虚函数表的大小
  • size_t _heap_capacity_at_last_gc; //上一次GC时的堆内存的容量
  • size_t _heap_used_at_last_gc;  //上一次GC时的堆内存的已使用的内存量

  Universe定义的方法大部分是读写属性的相关方法,重点关注Universe的初始化和下列方法的实现即可。因为Universe没有定义实例属性,都是静态属性和静态方法,所以Universe没有定义构造方法,初始化时也不需要new一个Universe,而是通过三个友元方法完成Universe的各静态属性的初始化,这三个友元方法的定义如下:

这三个方法都是在JVM启动时在init_globals()方法中依次调用的。 

2、LatestMethodCache / NarrowPtrStruct

   LatestMethodCache用来缓存Method*,调用方通过get_method方法获取的永远是该方法的最新版本,LatestMethodCache内部屏蔽了类重定义(Class Redefinition)时方法实现发生变更的问题。LatestMethodCache定义的属性如下:

_klass就是该方法所属的类的Klass,_method_idnum是该方法在Klass中的方法ID,实际是该方法在Klass方法数组中的序号,当类重定义时该方法对应的Method*可能发生改变,_method_idnum可能以为增加了新的方法也发生改变,但是_method_idnum会保证永远对应着原来的那个方法,从保证get_method方法返回的用于是该方法的最新版本。get_method方法的实现如下图:

 LatestMethodCache的init方法的实现如下图:

   NarrowPtrStruct是一个结构体,用来保存开启指针压缩时计算压缩指针真实地址的base地址等属性信息,其定义如下图:

base和shift属性的用法可以参考用于计算压缩指针真实地址oopDesc::decode_heap_oop_not_null方法的实现,如下图:

3、universe_init

     universe_init方法的执行依赖于codeCache_init 和stubRoutines_init 方法的成功执行,是最新被调用的universe初始化方法,主要用来初始化collectedHeap,Metaspace和TLAB等组件,其源码实现如下:

jint universe_init() {
  assert(!Universe::_fully_initialized, "called after initialize_vtables");
  //校验参数的合法
  guarantee(1 << LogHeapWordSize == sizeof(HeapWord),
         "LogHeapWordSize is incorrect.");
  //sizeof(oop)和sizeof(HeapWord)实际都是一个指针的大小
  guarantee(sizeof(oop) >= sizeof(HeapWord), "HeapWord larger than oop?");
  guarantee(sizeof(oop) % sizeof(HeapWord) == 0,
            "oop size is not not a multiple of HeapWord size");
  TraceTime timer("Genesis", TraceStartupTime);
  //计算部分重要的系统类的关键属性在oop中的偏移量,方便快速根据内存偏移读取属性值
  JavaClasses::compute_hard_coded_offsets();
  //初始化collectedHeap和TLABA
  jint status = Universe::initialize_heap();
  if (status != JNI_OK) {
    return status;
  }
  //初始化负责元空间内存管理的Metaspace
  Metaspace::global_initialize();

  // 初始化ClassLoaderData的_the_null_class_loader_data属性
  ClassLoaderData::init_null_class_loader_data();

  // 初始化属性
  Universe::_finalizer_register_cache = new LatestMethodCache();
  Universe::_loader_addClass_cache    = new LatestMethodCache();
  Universe::_pd_implies_cache         = new LatestMethodCache();
  Universe::_throw_illegal_access_error_cache = new LatestMethodCache();

  //UseSharedSpaces默认为true,表示为元数据使用共享空间
  if (UseSharedSpaces) {
    //初始化共享空间
    MetaspaceShared::initialize_shared_spaces();
    StringTable::create_table();
  } else {
    //不使用共享空间时,分别初始化各个组件,SymbolTable表示符号表,StringTable表示字符串表
    SymbolTable::create_table();
    StringTable::create_table();
    ClassLoader::create_package_info_table();

    if (DumpSharedSpaces) {
      MetaspaceShared::prepare_for_dumping();
    }
  }
  if (strlen(VerifySubSet) > 0) {
    Universe::initialize_verify_flags();
  }

  return JNI_OK;
}

jint Universe::initialize_heap() {
  //如果使用ParallelGC
  if (UseParallelGC) {

    Universe::_collectedHeap = new ParallelScavengeHeap();
  } else if (UseG1GC) {
    //如果使用G1GC
    G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt();
    g1p->initialize_all();
    G1CollectedHeap* g1h = new G1CollectedHeap(g1p);
    Universe::_collectedHeap = g1h;

  } else {
    //如果使用分代回收
    GenCollectorPolicy *gc_policy;
    //不同的回收策略
    if (UseSerialGC) {
      gc_policy = new MarkSweepPolicy();
    } else if (UseConcMarkSweepGC) {
      if (UseAdaptiveSizePolicy) {
        gc_policy = new ASConcurrentMarkSweepPolicy();
      } else {
        gc_policy = new ConcurrentMarkSweepPolicy();
      }
    } else { // default old generation
      gc_policy = new MarkSweepPolicy();
    }
    gc_policy->initialize_all();

    Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
  }
  //设置TLAB的最大值
  ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size());
  //初始化collectedHeap
  jint status = Universe::heap()->initialize();
  if (status != JNI_OK) {
    return status;
  }

#ifdef _LP64
  if (UseCompressedOops) {
     //根据不同的堆内存大小设置narrow_oop_shift
    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);

    } else {
      Universe::set_narrow_oop_base(0);

      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初始化是否正确
  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

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

4、universe2_init

     universe2_init方法是在universe_init方法执行完成后调用的,用来初始化基本类型的数组Klass,vmSymbols,SystemDictionary,JDK_Version等组件,其源码实现如下:

void universe2_init() {
  EXCEPTION_MARK;
  Universe::genesis(CATCH);
}

//用于检查当前线程是否存在待处理异常
#define EXCEPTION_MARK                           Thread* THREAD = NULL; ExceptionMark __em(THREAD);

ExceptionMark::ExceptionMark(Thread*& thread) {
 //thread赋值
  thread     = Thread::current();
  _thread    = thread;
  //检查当前线程是否存在异常
  if (_thread->has_pending_exception()) {
    //如果存在异常则清除
    oop exception = _thread->pending_exception();
    _thread->clear_pending_exception(); // Needed to avoid infinite recursion
    //打印异常
    exception->print();
    //报告致命错误
    fatal("ExceptionMark constructor expects no pending exceptions");
  }
}

//用来检查某个方法是否抛出了异常,通常是在该方法的调用方中使用此宏,且已经明确目标方法不会抛出异常
#define CATCH                              \
  THREAD); if (HAS_PENDING_EXCEPTION) {    \
    oop ex = PENDING_EXCEPTION;            \
    CLEAR_PENDING_EXCEPTION;               \
    ex->print();                           \
    ShouldNotReachHere();                  \
  } (void)(0

#define PENDING_EXCEPTION                        (((ThreadShadow*)THREAD)->pending_exception())
#define HAS_PENDING_EXCEPTION                    (((ThreadShadow*)THREAD)->has_pending_exception())
#define CLEAR_PENDING_EXCEPTION                  (((ThreadShadow*)THREAD)->clear_pending_exception())


void Universe::genesis(TRAPS) {
  ResourceMark rm;
  //FlagSetting通过构造函数临时将某个bool属性设置为指定值,在析构函数中将其恢复成原来的值
  { FlagSetting fs(_bootstrapping, true);
    //获取锁Compile_lock
    { MutexLocker mc(Compile_lock);

      //设置_base_vtable_size属性,实际就是取Object类的虚函数表的大小
      compute_base_vtable_size();
      //UseSharedSpaces表示为元数据使用共享空间,默认为true
      if (!UseSharedSpaces) {
        _boolArrayKlassObj      = TypeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);
        _charArrayKlassObj      = TypeArrayKlass::create_klass(T_CHAR,    sizeof(jchar),    CHECK);
        _singleArrayKlassObj    = TypeArrayKlass::create_klass(T_FLOAT,   sizeof(jfloat),   CHECK);
        _doubleArrayKlassObj    = TypeArrayKlass::create_klass(T_DOUBLE,  sizeof(jdouble),  CHECK);
        _byteArrayKlassObj      = TypeArrayKlass::create_klass(T_BYTE,    sizeof(jbyte),    CHECK);
        _shortArrayKlassObj     = TypeArrayKlass::create_klass(T_SHORT,   sizeof(jshort),   CHECK);
        _intArrayKlassObj       = TypeArrayKlass::create_klass(T_INT,     sizeof(jint),     CHECK);
        _longArrayKlassObj      = TypeArrayKlass::create_klass(T_LONG,    sizeof(jlong),    CHECK);

        _typeArrayKlassObjs[T_BOOLEAN] = _boolArrayKlassObj;
        _typeArrayKlassObjs[T_CHAR]    = _charArrayKlassObj;
        _typeArrayKlassObjs[T_FLOAT]   = _singleArrayKlassObj;
        _typeArrayKlassObjs[T_DOUBLE]  = _doubleArrayKlassObj;
        _typeArrayKlassObjs[T_BYTE]    = _byteArrayKlassObj;
        _typeArrayKlassObjs[T_SHORT]   = _shortArrayKlassObj;
        _typeArrayKlassObjs[T_INT]     = _intArrayKlassObj;
        _typeArrayKlassObjs[T_LONG]    = _longArrayKlassObj;

        ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data();

        _the_array_interfaces_array = MetadataFactory::new_array<Klass*>(null_cld, 2, NULL, CHECK);
        _the_empty_int_array        = MetadataFactory::new_array<int>(null_cld, 0, CHECK);
        _the_empty_short_array      = MetadataFactory::new_array<u2>(null_cld, 0, CHECK);
        _the_empty_method_array     = MetadataFactory::new_array<Method*>(null_cld, 0, CHECK);
        _the_empty_klass_array      = MetadataFactory::new_array<Klass*>(null_cld, 0, CHECK);
      }
    }
    //初始化符号表
    vmSymbols::initialize(CHECK);
    //初始化系统字典类
    SystemDictionary::initialize(CHECK);

    Klass* ok = SystemDictionary::Object_klass();

    _the_null_string            = StringTable::intern("null", CHECK);
    _the_min_jint_string       = StringTable::intern("-2147483648", CHECK);

    if (UseSharedSpaces) {
      //_the_array_interfaces_array表示数组对应的类默认实现的接口类,即Cloneable和Serializable接口
      assert(_the_array_interfaces_array->at(0) ==
             SystemDictionary::Cloneable_klass(), "u3");
      assert(_the_array_interfaces_array->at(1) ==
             SystemDictionary::Serializable_klass(), "u3");
    } else {
      // Set up shared interfaces array.  (Do this before supers are set up.)
      _the_array_interfaces_array->at_put(0, SystemDictionary::Cloneable_klass());
      _the_array_interfaces_array->at_put(1, SystemDictionary::Serializable_klass());
    }

    //boolArrayKlassObj方法返回_boolArrayKlassObj属性,initialize_basic_type_klass用来初始化Klass部分属性
    initialize_basic_type_klass(boolArrayKlassObj(), CHECK);
    initialize_basic_type_klass(charArrayKlassObj(), CHECK);
    initialize_basic_type_klass(singleArrayKlassObj(), CHECK);
    initialize_basic_type_klass(doubleArrayKlassObj(), CHECK);
    initialize_basic_type_klass(byteArrayKlassObj(), CHECK);
    initialize_basic_type_klass(shortArrayKlassObj(), CHECK);
    initialize_basic_type_klass(intArrayKlassObj(), CHECK);
    initialize_basic_type_klass(longArrayKlassObj(), CHECK);
  } // end of core bootstrapping

 //初始化_objectArrayKlassObj
  _objectArrayKlassObj = InstanceKlass::
    cast(SystemDictionary::Object_klass())->array_klass(1, CHECK);
  _objectArrayKlassObj->append_to_sibling_list();

  // 根据某些类是否存在来初步判断JDK的版本
  if (JDK_Version::is_partially_initialized()) {
    uint8_t jdk_version;
    Klass* k = SystemDictionary::resolve_or_null(
        vmSymbols::java_lang_management_MemoryUsage(), THREAD);
    CLEAR_PENDING_EXCEPTION; // ignore exceptions
    if (k == NULL) {
      k = SystemDictionary::resolve_or_null(
          vmSymbols::java_lang_CharSequence(), THREAD);
      CLEAR_PENDING_EXCEPTION; // ignore exceptions
      if (k == NULL) {
        k = SystemDictionary::resolve_or_null(
            vmSymbols::java_lang_Shutdown(), THREAD);
        CLEAR_PENDING_EXCEPTION; // ignore exceptions
        if (k == NULL) {
          jdk_version = 2;
        } else {
          jdk_version = 3;
        }
      } else {
        jdk_version = 4;
      }
    } else {
      jdk_version = 5;
    }
    //初始化JDK_Version
    JDK_Version::fully_initialize(jdk_version);
  }

  //初始化ClassLoaderData的_dependencies属性
  ClassLoaderData::the_null_class_loader_data()->init_dependencies(CHECK);

}

class FlagSetting {
  bool val;
  bool* flag;
 public:
  //flag指向目标属性,val是该属性原来的值,newValue是新值
  FlagSetting(bool& fl, bool newValue) { flag = &fl; val = fl; fl = newValue; }
  ~FlagSetting()                       { *flag = val; }
};

void Universe::compute_base_vtable_size() {
  _base_vtable_size = ClassLoader::compute_Object_vtable();
}

int ClassLoader::compute_Object_vtable() {
  // hardwired for JDK1.2 -- would need to duplicate class file parsing
  // code to determine actual value from file
  // Would be value '11' if finals were in vtable
  int JDK_1_2_Object_vtable_size = 5;
  return JDK_1_2_Object_vtable_size * vtableEntry::size();
}

void initialize_basic_type_klass(Klass* k, TRAPS) {
  Klass* ok = SystemDictionary::Object_klass();
  if (UseSharedSpaces) {
    ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
    //检查k的超类是否是Object
    assert(k->super() == ok, "u3");
    //设置Klass的_class_loader_data,_java_mirror等属性
    k->restore_unshareable_info(loader_data, Handle(), CHECK);
  } else {
    //将k的超类设置为Object
    k->initialize_supers(ok, CHECK);
  }
  //将k加入到其父类Object的子类链表上
  k->append_to_sibling_list();
}

static Klass* boolArrayKlassObj()                 { return _boolArrayKlassObj;   }

5、universe_post_init

      universe_post_init是在编译器等JVM主要组件都初始化完成后调用的,主要用来初始化Universe中定义的各种异常oop,CollectedHeap的再初始化,添加MemoryPool等,其源码实现如下:

bool universe_post_init() {
  //is_init_completed是指JVM是否完成初始化
  assert(!is_init_completed(), "Error: initialization not yet completed!");
  Universe::_fully_initialized = true;
  EXCEPTION_MARK;
  { ResourceMark rm;
    //确保解释器初始化完成,实际解释器会在此方法之前通过interpreter_init方法完成初始化
    Interpreter::initialize();      // needed for interpreter entry points
    //UseSharedSpaces默认为true,表示元数据是否使用共享空间
    if (!UseSharedSpaces) {
      HandleMark hm(THREAD);
      KlassHandle ok_h(THREAD, SystemDictionary::Object_klass());
      Universe::reinitialize_vtable_of(ok_h, CHECK_false);
      Universe::reinitialize_itables(CHECK_false);
    }
  }

  HandleMark hm(THREAD);
  Klass* k;
  instanceKlassHandle k_h;
    //初始化java.lang.Class 对应的klass数组
    Universe::_the_empty_class_klass_array = oopFactory::new_objArray(SystemDictionary::Class_klass(), 0, CHECK_false);

    //初始化不同场景下OutOfMemoryError对应的oop,实际都是一个类java_lang_OutOfMemoryError的实例
    k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false);
    k_h = instanceKlassHandle(THREAD, k);
    Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false);
    Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false);
    Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false);
    Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
    Universe::_out_of_memory_error_gc_overhead_limit =
      k_h->allocate_instance(CHECK_false);
    Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false);

    //初始化java_lang_NullPointerException
    // (this is currently used for a cheap & dirty solution in compiler exception handling)
    k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_NullPointerException(), true, CHECK_false);
    Universe::_null_ptr_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false);

    //初始化java_lang_ArithmeticException
    // (this is currently used for a cheap & dirty solution in compiler exception handling)
    k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_ArithmeticException(), true, CHECK_false);
    Universe::_arithmetic_exception_instance = InstanceKlass::cast(k)->allocate_instance(CHECK_false);
    
    //初始化java_lang_VirtualMachineError
    k = SystemDictionary::resolve_or_fail(
      vmSymbols::java_lang_VirtualMachineError(), true, CHECK_false);
    bool linked = InstanceKlass::cast(k)->link_class_or_fail(CHECK_false);
    if (!linked) {
      tty->print_cr("Unable to link/verify VirtualMachineError class");
      return false; // initialization failed
    }
    Universe::_virtual_machine_error_instance =
      InstanceKlass::cast(k)->allocate_instance(CHECK_false);
    Universe::_vm_exception = InstanceKlass::cast(k)->allocate_instance(CHECK_false);
  //DumpSharedSpaces默认为false,如果为true,表示JVM会将加载的类Dump到一个文件上给其他的JVM使用
  if (!DumpSharedSpaces) {
    //设置不同类型的OutOfMemoryError的异常提示
    Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg());

    msg = java_lang_String::create_from_str("Metaspace", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg());
    msg = java_lang_String::create_from_str("Compressed class space", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg());

    msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg());

    msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());

    msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false);
    java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg());

    msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
    java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());

    // Setup the array of errors that have preallocated backtrace
    k = Universe::_out_of_memory_error_java_heap->klass();
    assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error");
    k_h = instanceKlassHandle(THREAD, k);

    //初始化_preallocated_out_of_memory_error_array,PreallocatedOutOfMemoryErrorCount默认值为4
    int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
    Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false);
    for (int i=0; i<len; i++) {
      oop err = k_h->allocate_instance(CHECK_false);
      Handle err_h = Handle(THREAD, err);
      java_lang_Throwable::allocate_backtrace(err_h, CHECK_false);
      Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h());
    }
    Universe::_preallocated_out_of_memory_error_avail_count = (jint)len;
  }


  // 初始化_finalizer_register_cache属性,对应java_lang_ref_Finalizer类的register(Object finalizee)方法
  InstanceKlass::cast(SystemDictionary::Finalizer_klass())->link_class(CHECK_false);
  Method* m = InstanceKlass::cast(SystemDictionary::Finalizer_klass())->find_method(
                                  vmSymbols::register_method_name(),
                                  vmSymbols::register_method_signature());
  if (m == NULL || !m->is_static()) {
    tty->print_cr("Unable to link/verify Finalizer.register method");
    return false; // initialization failed (cannot throw exception yet)
  }
  Universe::_finalizer_register_cache->init(
    SystemDictionary::Finalizer_klass(), m);

  //初始化_throw_illegal_access_error_cache属性,对应 Unsafe类的throwIllegalAccessError() 方法
  InstanceKlass::cast(SystemDictionary::misc_Unsafe_klass())->link_class(CHECK_false);
  m = InstanceKlass::cast(SystemDictionary::misc_Unsafe_klass())->find_method(
                                  vmSymbols::throwIllegalAccessError_name(),
                                  vmSymbols::void_method_signature());
  if (m != NULL && !m->is_static()) {
   
    tty->print_cr("Unable to link/verify Unsafe.throwIllegalAccessError method");
    return false; // initialization failed (cannot throw exception yet)
  }
  Universe::_throw_illegal_access_error_cache->init(
    SystemDictionary::misc_Unsafe_klass(), m);

  //初始化属性_loader_addClass_cache,对应sun_reflect_DelegatingClassLoader类的addClass方法
  InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->link_class(CHECK_false);
  m = InstanceKlass::cast(SystemDictionary::ClassLoader_klass())->find_method(vmSymbols::addClass_name(), vmSymbols::class_void_signature());
  if (m == NULL || m->is_static()) {
    tty->print_cr("Unable to link/verify ClassLoader.addClass method");
    return false; // initialization failed (cannot throw exception yet)
  }
  Universe::_loader_addClass_cache->init(
    SystemDictionary::ClassLoader_klass(), m);

  //初始化属性_pd_implies_cache,对应java_security_ProtectionDomain类的impliesCreateAccessControlContext方法
  InstanceKlass::cast(SystemDictionary::ProtectionDomain_klass())->link_class(CHECK_false);
  m = InstanceKlass::cast(SystemDictionary::ProtectionDomain_klass())->
            find_method(vmSymbols::impliesCreateAccessControlContext_name(),
                        vmSymbols::void_boolean_signature());
  // Allow NULL which should only happen with bootstrapping.
  if (m != NULL) {
    if (m->is_static()) {
      tty->print_cr("ProtectionDomain.impliesCreateAccessControlContext() has the wrong linkage");
      return false; // initialization failed
    }
    Universe::_pd_implies_cache->init(
      SystemDictionary::ProtectionDomain_klass(), m);
  }

  //初始化jvm.cpp中定义的基类类型间的转换方法,如IntBitsToFloatFn,实际取的是包装类的方法,对应java/lang/Float类的intBitsToFloat方法
  initialize_converter_functions();

  //保证在第一次GC前调用,获取当前堆的容量和已使用内存,保存到_heap_capacity_at_last_gc和_heap_used_at_last_gc属性中
  {
    MutexLocker x(Heap_lock);
    Universe::update_heap_info_at_gc();
  }

  //Java堆的初始化
  Universe::heap()->post_initialize();

  //初始化元空间的性能统计,开启UsePerfData时才有效,默认是false
  MetaspaceCounters::initialize_performance_counters();
  CompressedClassSpaceCounters::initialize_performance_counters();
  
  //添加元空间对应的memory_pool
  MemoryService::add_metaspace_memory_pools();
  //添加Java堆对应的memory_pool
  MemoryService::set_universe_heap(Universe::_collectedHeap);
#
  return true;
}

void Universe::update_heap_info_at_gc() {
  _heap_capacity_at_last_gc = heap()->capacity();
  _heap_used_at_last_gc     = heap()->used();
}

6、initialize_basic_type_mirrors

     上述三个方法把Universe定义的静态属性基本都初始化了,除了基本类型对应的mirror_klass属性,如_int_mirror,_float_mirror等,这些属性都在initialize_basic_type_mirrors方法中完成,其实现如下:

该方法的调用链如下:

 

即执行universe2_init方法时会初始化上述属性。

7、reserve_heap

      reserve_heap方法用于给Java堆申请一段连续的内存空间,同时计算在开启指针压缩时的指针基地址,所有的垃圾回收器在初始化的时候都会调用此方法,该方法的调用链如下图:

参考universe2_init方法中Java堆的初始化可知,Java堆就只有上图中的三种类型。

ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
  //校验参数
  assert(alignment <= Arguments::conservative_max_heap_alignment(),
      err_msg("actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT,
          alignment, Arguments::conservative_max_heap_alignment()));
  //heap_size取整
  size_t total_reserved = align_size_up(heap_size, alignment);
  //使用指针压缩时堆空间不能超过OopEncodingHeapMax,是计算出来的,32G
  assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
      "heap size is too big for compressed oops");
  
  //是否使用大内存页,UseLargePages默认是false
  bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size());
  assert(!UseLargePages
      || UseParallelGC
      || use_large_pages, "Wrong alignment to use large pages");
   //计算Java堆的基地址
  char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);
  //在执行构造方法的时候会向操作系统申请一段连续的内存空间
  ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);

  if (UseCompressedOops) {
     //如果申请失败,即该地址已经被分配了,则重试重新申请,每次重试时使用的NARROW_OOP_MODE不同
    if (addr != NULL && !total_rs.is_reserved()) {
      addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);

      ReservedHeapSpace total_rs0(total_reserved, alignment,
          use_large_pages, addr);

      if (addr != NULL && !total_rs0.is_reserved()) {
        //继续重试
        addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);
        assert(addr == NULL, "");

        ReservedHeapSpace total_rs1(total_reserved, alignment,
            use_large_pages, addr);
        total_rs = total_rs1;
      } else {
        total_rs = total_rs0;
      }
    }
  }

  //重试依然失败,抛出异常
  if (!total_rs.is_reserved()) {
    vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K));
    return total_rs;
  }

  if (UseCompressedOops) {
    //设置压缩指针的基地址
    address base = (address)(total_rs.base() - os::vm_page_size());
    Universe::set_narrow_oop_base(base);
  }
  return total_rs;
}

char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
  //校验这些参数已经是取整过了
  assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
  assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be");
  assert(is_size_aligned(heap_size, alignment), "Must be");

  //HeapBaseMinAddress表示Java堆的内存基地址,x86下默认是2G,将HeapBaseMinAddress按照alignment取整
  uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);

  size_t base = 0;
//如果是64位系统
#ifdef _LP64
  //如果开启指针压缩,64位下默认为true
  if (UseCompressedOops) {
     //校验mode合法
    assert(mode == UnscaledNarrowOop  ||
           mode == ZeroBasedNarrowOop ||
           mode == HeapBasedNarrowOop, "mode is invalid");
    const size_t total_size = heap_size + heap_base_min_address_aligned;
    //根据不同的NARROW_OOP_MODE分别计算
    if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
      base = heap_base_min_address_aligned;

    // If the total size is small enough to allow UnscaledNarrowOop then
    // just use UnscaledNarrowOop.
    } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {
      if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) &&
          (Universe::narrow_oop_shift() == 0)) {
        // Use 32-bits oops without encoding and
        // place heap's top on the 4Gb boundary
        base = (UnscaledOopHeapMax - heap_size);
      } else {
        // Can't reserve with NarrowOopShift == 0
        Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);

        if (mode == UnscaledNarrowOop ||
            mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) {

          // Use zero based compressed oops with encoding and
          // place heap's top on the 32Gb boundary in case
          // total_size > 4Gb or failed to reserve below 4Gb.
          uint64_t heap_top = OopEncodingHeapMax;

          // For small heaps, save some space for compressed class pointer
          // space so it can be decoded with no base.
          if (UseCompressedClassPointers && !UseSharedSpaces &&
              OopEncodingHeapMax <= 32*G) {

            uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
            assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space,
                   alignment), "difference must be aligned too");
            uint64_t new_top = OopEncodingHeapMax-class_space;

            if (total_size <= new_top) {
              heap_top = new_top;
            }
          }

          // Align base to the adjusted top of the heap
          base = heap_top - heap_size;
        }
      }
    } else {
      // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or
      // HeapBasedNarrowOop encoding was requested.  So, can't reserve below 32Gb.
      Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
    }

    // Set narrow_oop_base and narrow_oop_use_implicit_null_checks
    // used in ReservedHeapSpace() constructors.
    // The final values will be set in initialize_heap() below.
    if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {
      // Use zero based compressed oops
      Universe::set_narrow_oop_base(NULL);
      // 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);
    } else {
      // Set to a non-NULL value so the ReservedSpace ctor computes
      // the correct no-access prefix.
      // The final value will be set in initialize_heap() below.
      Universe::set_narrow_oop_base((address)UnscaledOopHeapMax);
    }
  }
#endif

  assert(is_ptr_aligned((char*)base, alignment), "Must be");
  return (char*)base; // also return NULL (don't care) for 32-bit VM
}

上述方法中用到的NARROW_OOP_MODE的定义如下:

ReservedSpace类和ReservedHeapSpace类的说明参考《Hotspot 内存管理之CodeCache 源码解析》 中的讲解。

8、oops_do

     oops_do用于以Universe定义的各种oop作为根节点遍历引用该oop的对象,垃圾回收时调用,该方法的实现如下图:

该方法的调用链如下:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值