该函数的入口在init.cpp->init_globals(),然后再调用universe.cpp->universe2_init()函数,实际执行的函数是Universe::genesis,所以从这开始源码的解析。解析前先了解一下Klass的概念,大家思考个问题:我们编写的java类在JVM中是以何种形式存在的呢?
答:其实他就是以Klass类存在的,Klass类就是java类在jvm中存在的形式。下图为Klass类的继承结构
图20-10
void Universe::genesis(TRAPS) {
ResourceMark rm;
{ FlagSetting fs(_bootstrapping, true);
{ MutexLocker mc(Compile_lock);
// 计算Object类的虚函数表占用内存大小,实现细节看`章节20.2.1.2`
compute_base_vtable_size();
if (!UseSharedSpaces) {
// 下面创建8个基础类型的数组类型的对象,细节看`章节20.2.2`
_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数组中,方便后面使用
_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;
// 根加载器的CLD
ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data();
// 在null_cld中创建一个Array对象的数组,长度为2,元素默认值都为NULL
_the_array_interfaces_array = MetadataFactory::new_array<Klass*>(null_cld, 2, NULL, CHECK);
// 在null_cld中创建一个Array对象的数组,长度为0
_the_empty_int_array = MetadataFactory::new_array<int>(null_cld, 0, CHECK);
// 在null_cld中创建一个Array对象的数组,长度为0
_the_empty_short_array = MetadataFactory::new_array<u2>(null_cld, 0, CHECK);
// 在null_cld中创建一个Array对象的数组,长度为0
_the_empty_method_array = MetadataFactory::new_array<Method*>(null_cld, 0, CHECK);
// 在null_cld中创建一个Array对象的数组,长度为0
_the_empty_klass_array = MetadataFactory::new_array<Klass*>(null_cld, 0, CHECK);
}
}
// 下面代码逻辑将放在 `章节20.5` 和 `章节20.5` 中讲
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) {
// Verify shared interfaces array.
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());
}
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
// Maybe this could be lifted up now that object array can be initialized
// during the bootstrapping.
// OLD
// Initialize _objectArrayKlass after core bootstraping to make
// sure the super class is set up properly for _objectArrayKlass.
// ---
// NEW
// Since some of the old system object arrays have been converted to
// ordinary object arrays, _objectArrayKlass will be loaded when
// SystemDictionary::initialize(CHECK); is run. See the extra check
// for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl.
_objectArrayKlassObj = InstanceKlass::
cast(SystemDictionary::Object_klass())->array_klass(1, CHECK);
// OLD
// Add the class to the class hierarchy manually to make sure that
// its vtable is initialized after core bootstrapping is completed.
// ---
// New
// Have already been initialized.
_objectArrayKlassObj->append_to_sibling_list();
// Compute is_jdk version flags.
// Only 1.3 or later has the java.lang.Shutdown class.
// Only 1.4 or later has the java.lang.CharSequence interface.
// Only 1.5 or later has the java.lang.management.MemoryUsage class.
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::fully_initialize(jdk_version);
}
#ifdef ASSERT
if (FullGCALot) {
// Allocate an array of dummy objects.
// We'd like these to be at the bottom of the old generation,
// so that when we free one and then collect,
// (almost) the whole heap moves
// and we find out if we actually update all the oops correctly.
// But we can't allocate directly in the old generation,
// so we allocate wherever, and hope that the first collection
// moves these objects to the bottom of the old generation.
// We can allocate directly in the permanent generation, so we do.
int size;
if (UseConcMarkSweepGC) {
warning("Using +FullGCALot with concurrent mark sweep gc "
"will not force all objects to relocate");
size = FullGCALotDummies;
} else {
size = FullGCALotDummies * 2;
}
objArrayOop naked_array = oopFactory::new_objArray(SystemDictionary::Object_klass(), size, CHECK);
objArrayHandle dummy_array(THREAD, naked_array);
int i = 0;
while (i < size) {
// Allocate dummy in old generation
oop dummy = InstanceKlass::cast(SystemDictionary::Object_klass())->allocate_instance(CHECK);
dummy_array->obj_at_put(i++, dummy);
}
{
// Only modify the global variable inside the mutex.
// If we had a race to here, the other dummy_array instances
// and their elements just get dropped on the floor, which is fine.
MutexLocker ml(FullGCALot_lock);
if (_fullgc_alot_dummy_array == NULL) {
_fullgc_alot_dummy_array = dummy_array();
}
}
assert(i == _fullgc_alot_dummy_array->length(), "just checking");
}
#endif
// Initialize dependency array for null class loader
ClassLoaderData::the_null_class_loader_data()->init_dependencies(CHECK);
}
void Universe::compute_base_vtable_size() {
// 计算Object类的虚函数表占用内存大小
_base_vtable_size = ClassLoader::compute_Object_vtable();
}
classLoader.cpp
在Java中所有的类都是默认继承自Object类的,所以这里要计算Object类的初始 vtable的大小,默认JDK_1_2_Object_vtable_size = 5,为什么是5呢?因为Object提供了5个可使用和继承的方法,如下:
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}
protected void finalize() throws Throwable { }
int ClassLoader::compute_Object_vtable() {
int JDK_1_2_Object_vtable_size = 5; // 5个
// 占用内存为5 * 每个的大小(vtableEntry::size())
return JDK_1_2_Object_vtable_size * vtableEntry::size();
}
const char* TypeArrayKlass::external_name(BasicType type) {
switch (type) {
// 看着下面这些[开头的类型是不是很熟悉,在Java中打印基础类型的数组对象时,就会出现下面符号中的一种,也就是虚拟机层面给各基础类型数组的类型简称
case T_BOOLEAN: return "[Z";
case T_CHAR: return "[C";
case T_FLOAT: return "[F";
case T_DOUBLE: return "[D";
case T_BYTE: return "[B";
case T_SHORT: return "[S";
case T_INT: return "[I";
case T_LONG: return "[J";
default: ShouldNotReachHere();
}
return NULL;
}
static inline Klass* create_klass(BasicType type, int scale, TRAPS) {
// 创建type类型的基础类型的数组类型
TypeArrayKlass* tak = create_klass(type, external_name(type), CHECK_NULL);
assert(scale == (1 << tak->log2_element_size()), "scale must check out");
return tak;
}
TypeArrayKlass* TypeArrayKlass::create_klass(BasicType type,
const char* name_str, TRAPS) {
Symbol* sym = NULL;
if (name_str != NULL) {
// 把name_str先创建一个符号,并加入到符号表SymbolTable中,看到符号表是不是眼熟,可以回来看`章节19.2`
sym = SymbolTable::new_permanent_symbol(name_str, CHECK_NULL);
}
// 拿到null加载器的CLD,也就是Java中所谓的根加载器
ClassLoaderData* null_loader_data = ClassLoaderData::the_null_class_loader_data();
// 给数组类型的Klass分配内存,看`章节20.2.2.2`
TypeArrayKlass* ak = TypeArrayKlass::allocate(null_loader_data, type, sym, CHECK_NULL);
// 将当前创建的klass ak,添加到根加载器的CLD的klasses链表中
null_loader_data->add_class(ak);
// Call complete_create_array_klass after all instance variables have been initialized.
/*
* 通过Java我们知道,每个类都有一个对应的java.lang.Class对象,同理在JVM中也需要有这么一个对象,在JVM中,
* 该对象用InstanceMirrorKlass的对象来表示,所以这一步就是创建该数组类型的InstanceMirrorKlass对象。
* 由`图20-10`,得到InstanceMirrorKlass是继承自InstanceKlass的,并且在InstanceMirrorKlass中定义了很多
* 操作InstanceKlass类对象的函数,所以在Java中,java.lang.Class可以用来做反射处理。
*/
complete_create_array_klass(ak, ak->super(), CHECK_NULL);
return ak;
}
TypeArrayKlass* TypeArrayKlass::allocate(ClassLoaderData* loader_data, BasicType type, Symbol* name, TRAPS) {
assert(TypeArrayKlass::header_size() <= InstanceKlass::header_size(),
"array klasses must be same size as InstanceKlass");
// 先计算要分配的内存大小
int size = ArrayKlass::static_size(TypeArrayKlass::header_size());
// 在元空间中分配内存,new 操作看`章节20.2.3.1`,TypeArrayKlass 构造函数实现看`章节20.2.2.3`
return new (loader_data, size, THREAD) TypeArrayKlass(type, name);
}
TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name) { // 调用父类构造函数
set_layout_helper(array_layout_helper(type));
assert(oop_is_array(), "sanity");
assert(oop_is_typeArray(), "sanity");
// 设置该数组的最大长度
set_max_length(arrayOopDesc::max_array_length(type));
assert(size() >= TypeArrayKlass::header_size(), "bad size");
// 设置该数组类的CLD为根加载器Data,也就是说基础数组类型的加载都是通过根加载器去加载的
set_class_loader_data(ClassLoaderData::the_null_class_loader_data());
}
父类ArrayKlass构造函数
ArrayKlass::ArrayKlass(Symbol* name) {
set_name(name);// 设置名字
// 这里默认设置超类为NULL
set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
set_layout_helper(Klass::_lh_neutral_value);
set_dimension(1);
set_higher_dimension(NULL);
set_lower_dimension(NULL);
set_component_mirror(NULL);
// Object类的vtable大小,这个在`章节20.2.1.2`中有介绍
int vtable_size = Universe::base_vtable_size();
set_vtable_length(vtable_size);
set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
JFR_ONLY(INIT_ID(this);)
}
void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() {
// 细节看`章节20.2.4.1`
return Metaspace::allocate(loader_data, word_size, /*read_only*/false,
MetaspaceObj::ClassType, THREAD);
}
MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
bool read_only, MetaspaceObj::Type type, TRAPS) {
if (HAS_PENDING_EXCEPTION) {
assert(false, "Should not allocate with exception pending");
return NULL; // caller does a CHECK_NULL too
}
assert(loader_data != NULL, "Should never pass around a NULL loader_data. "
"ClassLoaderData::the_null_class_loader_data() should have been used.");
// DumpSharedSpaces表示多Java进程共享,这里不涉及多Java进程共享,这一步不会走
if (DumpSharedSpaces) {
assert(type > MetaspaceObj::UnknownType && type < MetaspaceObj::_number_of_types, "sanity");
Metaspace* space = read_only ? loader_data->ro_metaspace() : loader_data->rw_metaspace();
MetaWord* result = space->allocate(word_size, NonClassType);
if (result == NULL) {
report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite);
}
if (PrintSharedSpaces) {
space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size));
}
// Zero initialize.
Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
return result;
}
// 确定要分配的内存内容的类型,类的创建都是ClassType
MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;
// 尝试分配元数据。loader_data->metaspace_non_null()函数(实现细节看`章节20.3`)可以拿到Metaspace的指针指向的元空间对象,然后再通过allocate函数在元空间中分配内存,allocate分配看后面描述
MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype);
if (result == NULL) {
tracer()->report_metaspace_allocation_failure(loader_data, word_size, type, mdtype);
// 分配失败,可能是内存不足,所以启动GC
if (is_init_completed()) {
// 尝试GC 清空一些内存
result = Universe::heap()->collector_policy()->satisfy_failed_metadata_allocation(
loader_data, word_size, mdtype);
}
}
// 启动GC 后还是失败,那就直接报告oom错误
if (result == NULL) {
report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL);
}
// Zero initialize.
Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
// 返回分配后的内存首地址
return result;
}
allocate 从SpaceManager中分配内存
MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) {
// class_vsm() 和 vsm() 取出的都是SpaceManager对象,直接往下看
if (is_class_space_allocation(mdtype)) {
return class_vsm()->allocate(word_size);
} else {
return vsm()->allocate(word_size);
}
}
从SpaceManager中分配
MetaWord* SpaceManager::allocate(size_t word_size) {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t raw_word_size = get_raw_word_size(word_size);
BlockFreelist* fl = block_freelists();
MetaWord* p = NULL;
// Allocation from the dictionary is expensive in the sense that
// the dictionary has to be searched for a size. Don't allocate
// from the dictionary until it starts to get fat. Is this
// a reasonable policy? Maybe an skinny dictionary is fast enough
// for allocations. Do some profiling. JJJ
if (fl->total_size() > allocation_from_dictionary_limit) {
p = fl->get_block(raw_word_size);
}
if (p == NULL) {
// 直接看这一行
p = allocate_work(raw_word_size);
}
return p;
}
正式分配
MetaWord* SpaceManager::allocate_work(size_t word_size) {
assert_lock_strong(_lock);
#ifdef ASSERT
if (Metadebug::test_metadata_failure()) {
return NULL;
}
#endif
// Is there space in the current chunk?
MetaWord* result = NULL;
// For DumpSharedSpaces, only allocate out of the current chunk which is
// never null because we gave it the size we wanted. Caller reports out
// of memory if this returns null.
if (DumpSharedSpaces) {
assert(current_chunk() != NULL, "should never happen");
inc_used_metrics(word_size);
return current_chunk()->allocate(word_size); // caller handles null result
}
// current_chunk() 函数拿到当前在用的chunk,这个chunk就是`章节20.3.2`中 initialize_first_chunk()函数实现里面设置的,然后再通过allocate分配,怎么分配的呢,继续往下看
if (current_chunk() != NULL) {
result = current_chunk()->allocate(word_size);
}
// 分配不成功,肯定是容量不够了,这一步就是扩容
if (result == NULL) {
result = grow_and_allocate(word_size);
}
if (result != NULL) {
inc_used_metrics(word_size);
assert(result != (MetaWord*) chunks_in_use(MediumIndex),
"Head of the list is being allocated");
}
return result;
}
从Metachunk中分配
看代码实现,非常简单,就是把_top上移word_size个字,读者只需把它理解成一个带刻度的水缸,往里面加水时,刻度值上升,就这么简单。
MetaWord* Metachunk::allocate(size_t word_size) {
MetaWord* result = NULL;
// If available, bump the pointer to allocate.
if (free_word_size() >= word_size) {
result = _top;
_top = _top + word_size;
}
return result;
}
为什么要创建Metaspace呢?
答:在元空间分配元数据内存时都需要元空间对象Metaspace实例来操作?在第十八章
中虽然有对元空间的创建与分配讲解,但是并没有对元空间实际存储数据逻辑和真正的内存空间分配描述,第十八章
只是描述了对元空间实际分配元数据内存前的一些准备工作,比如划出一块大的空间作为元空间、再将大空间划成一块块小的chunk、再通过链表管理起来等等。这一章节就是讲具体的元数据的分配。
Metaspace* ClassLoaderData::metaspace_non_null() {
assert(!DumpSharedSpaces, "wrong metaspace!");
// If the metaspace has not been allocated, create a new one. Might want
// to create smaller arena for Reflection class loaders also.
// The reason for the delayed allocation is because some class loaders are
// simply for delegating with no metadata of their own.
if (_metaspace == NULL) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
// Check again if metaspace has been allocated while we were getting this lock.
if (_metaspace != NULL) {
return _metaspace;
}
if (this == the_null_class_loader_data()) {
assert (class_loader() == NULL, "Must be");
// 直接看这一行,Metaspace的创建看`章节20.3.2`
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
} else if (is_anonymous()) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
} else {
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType));
}
}
// 把创建后的metaspace对象实例返回
return _metaspace;
}
构造函数
Metaspace::Metaspace(Mutex* lock, MetaspaceType type) {
initialize(lock, type);
}
初始化函数
void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
verify_global_initialization();
// 创建 SpaceManager 对象,分配元数据(主要是符号、字符串等)需要用到,本章节的后面有对这对象创建的讲解
_vsm = new SpaceManager(NonClassType, lock);
if (using_class_space()) {
// 创建 SpaceManager 对象,分配类时需要用到
_class_vsm = new SpaceManager(ClassType, lock);
} else {
_class_vsm = NULL;
}
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// 这一步就是从`第十八章`中分配的空闲chunk链表中找出一个适合当前分配大小(前面讲过,MetaChunk块有三种大小,取一个适合自己的就行)的MetaChunk块对象,并把它添加到 SpaceManager 对象(在这里表示 _vsm)来管理
initialize_first_chunk(type, NonClassType);
// 同上,这是取出一块MetaChunk来存放类数据,并用 SpaceManager 对象(在这里表示 _class_vsm)管理
if (using_class_space()) {
initialize_first_chunk(type, ClassType);
}
_alloc_record_head = NULL;
_alloc_record_tail = NULL;
}
创建SpaceManager对象
SpaceManager对象就是管理元数据分配在哪个chunk,这个对象的创建很简单,就是做一些初始值的赋值
SpaceManager::SpaceManager(Metaspace::MetadataType mdtype,
Mutex* lock) :
_mdtype(mdtype),
_allocated_blocks_words(0),
_allocated_chunks_words(0),
_allocated_chunks_count(0),
_lock(lock)
{
initialize();
}
void SpaceManager::initialize() {
Metadebug::init_allocation_fail_alot_count();
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
_chunks_in_use[i] = NULL; // 把所有chunk已用状态设置为null
}
_current_chunk = NULL;
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr("SpaceManager(): " PTR_FORMAT, this);
}
}