void vm_init_globals() {
// 验证ThreadShadow的实现,主要是验证线程对象的_pending_exception属性位置,_pending_exception后面用到时再讲
check_ThreadShadow();
// 基础类型初始化,看`章节10.1.2.1`
basic_types_init();
eventlog_init(); // 各种事件日志初始化,不影响主流程,先忽略
mutex_init(); // 各种互斥锁的初始化,不影响主流程,先忽略
// 内存(块)池初始化,提前分配内存,类似线程池,提升内存分配的性能,分配细节看`章节10.1.3`
chunkpool_init();
/*
* 热点性能数据存储内存初始化。热点性能数据的收集通过-XX:+UsePerfData控制开通与否,默认是开通的。
* 启用 PerfData 后,HotSpot JVM 会在目录下为每个 JVM 进程创建一个文件。通过工具扫描此目录
* 以查找正在运行的 JVM。如果禁用 PerfData,这些工具将不会自动发现JVM
* jstat 是依赖于热点性能数据的标准 JDK 工具之一。 不适用于禁用了性能数据的 JVM。
* 细节上,这块也可以忽略
*/
perfMemory_init();
}
void basic_types_init() {
// 下面的操作就是验证各个类型的在32位和64位机器上的内存占用位数
#ifdef ASSERT
#ifdef _LP64
assert(min_intx == (intx)CONST64(0x8000000000000000), "correct constant");
assert(max_intx == CONST64(0x7FFFFFFFFFFFFFFF), "correct constant");
assert(max_uintx == CONST64(0xFFFFFFFFFFFFFFFF), "correct constant");
assert( 8 == sizeof( intx), "wrong size for basic type");
assert( 8 == sizeof( jobject), "wrong size for basic type");
#else
assert(min_intx == (intx)0x80000000, "correct constant");
assert(max_intx == 0x7FFFFFFF, "correct constant");
assert(max_uintx == 0xFFFFFFFF, "correct constant");
assert( 4 == sizeof( intx), "wrong size for basic type");
assert( 4 == sizeof( jobject), "wrong size for basic type");
#endif
assert( (~max_juint) == 0, "max_juint has all its bits");
assert( (~max_uintx) == 0, "max_uintx has all its bits");
assert( (~max_julong) == 0, "max_julong has all its bits");
assert( 1 == sizeof( jbyte), "wrong size for basic type");
assert( 2 == sizeof( jchar), "wrong size for basic type");
assert( 2 == sizeof( jshort), "wrong size for basic type");
assert( 4 == sizeof( juint), "wrong size for basic type");
assert( 4 == sizeof( jint), "wrong size for basic type");
assert( 1 == sizeof( jboolean), "wrong size for basic type");
assert( 8 == sizeof( jlong), "wrong size for basic type");
assert( 4 == sizeof( jfloat), "wrong size for basic type");
assert( 8 == sizeof( jdouble), "wrong size for basic type");
assert( 1 == sizeof( u1), "wrong size for basic type");
assert( 2 == sizeof( u2), "wrong size for basic type");
assert( 4 == sizeof( u4), "wrong size for basic type");
// 验证各个基础类型代表的字符,比如B代表byte,C代表char,依此类推
int num_type_chars = 0;
for (int i = 0; i < 99; i++) {
if (type2char((BasicType)i) != 0) {
assert(char2type(type2char((BasicType)i)) == i, "proper inverses");
num_type_chars++;
}
}
// 类型个数只能是11个,8个基础类型 + 1个void类型 + 1个object类型 + 1个array类型
assert(num_type_chars == 11, "must have tested the right number of mappings");
assert(char2type(0) == T_ILLEGAL, "correct illegality");
{
for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
BasicType vt = (BasicType)i;
BasicType ft = type2field[vt];
switch (vt) {
// the following types might plausibly show up in memory layouts:
case T_BOOLEAN:
case T_BYTE:
case T_CHAR:
case T_SHORT:
case T_INT:
case T_FLOAT:
case T_DOUBLE:
case T_LONG:
case T_OBJECT:
case T_ADDRESS: // random raw pointer
case T_METADATA: // metadata pointer
case T_NARROWOOP: // compressed pointer
case T_NARROWKLASS: // compressed klass pointer
case T_CONFLICT: // might as well support a bottom type
case T_VOID: // padding or other unaddressed word
// layout type must map to itself
assert(vt == ft, "");
break;
default:
// non-layout type must map to a (different) layout type
assert(vt != ft, "");
assert(ft == type2field[ft], "");
}
// every type must map to same-sized layout type:
assert(type2size[vt] == type2size[ft], "");
}
}
// These are assumed, e.g., when filling HeapWords with juints.
assert(is_power_of_2(sizeof(juint)), "juint must be power of 2");
assert(is_power_of_2(HeapWordSize), "HeapWordSize must be power of 2");
assert((size_t)HeapWordSize >= sizeof(juint),
"HeapWord should be at least as large as juint");
assert(sizeof(NULL) == sizeof(char*), "NULL must be same size as pointer");
#endif
// 设置Java与OS的线程优先级对应关系,默认都是-1(JavaPriority1_To_OSPriority到JavaPriority10_To_OSPriority初始值都是-1),也就是没有优先级
if( JavaPriority1_To_OSPriority != -1 )
os::java_to_os_priority[1] = JavaPriority1_To_OSPriority;
if( JavaPriority2_To_OSPriority != -1 )
os::java_to_os_priority[2] = JavaPriority2_To_OSPriority;
if( JavaPriority3_To_OSPriority != -1 )
os::java_to_os_priority[3] = JavaPriority3_To_OSPriority;
if( JavaPriority4_To_OSPriority != -1 )
os::java_to_os_priority[4] = JavaPriority4_To_OSPriority;
if( JavaPriority5_To_OSPriority != -1 )
os::java_to_os_priority[5] = JavaPriority5_To_OSPriority;
if( JavaPriority6_To_OSPriority != -1 )
os::java_to_os_priority[6] = JavaPriority6_To_OSPriority;
if( JavaPriority7_To_OSPriority != -1 )
os::java_to_os_priority[7] = JavaPriority7_To_OSPriority;
if( JavaPriority8_To_OSPriority != -1 )
os::java_to_os_priority[8] = JavaPriority8_To_OSPriority;
if( JavaPriority9_To_OSPriority != -1 )
os::java_to_os_priority[9] = JavaPriority9_To_OSPriority;
if(JavaPriority10_To_OSPriority != -1 )
os::java_to_os_priority[10] = JavaPriority10_To_OSPriority;
// Set the size of basic types here (after argument parsing but before
// stub generation).
if (UseCompressedOops) { // 压缩指针,为了降低学习难度,又不失去完整流程的学习,先忽略压缩指针情况
// Size info for oops within java objects is fixed
heapOopSize = jintSize;
LogBytesPerHeapOop = LogBytesPerInt;
LogBitsPerHeapOop = LogBitsPerInt;
BytesPerHeapOop = BytesPerInt;
BitsPerHeapOop = BitsPerInt;
} else {
// 堆对象指针内存占用大小,32位机器占4字节,64位机器占8字节
heapOopSize = oopSize;
// 每个字(word)的字节的幂次方,32位机器为2,64位机器为3
LogBytesPerHeapOop = LogBytesPerWord;
// 每个堆对象指针的位数的幂次方,32位机器为5,64位机器为6
LogBitsPerHeapOop = LogBitsPerWord;
// 每个字(word)的字节的数,32位机器为4字节,64位机器为8字节,
BytesPerHeapOop = BytesPerWord;
// 每个堆对象指针的位数,32位机器为32位,64位机器为64位
BitsPerHeapOop = BitsPerWord;
}
// object和array在jvm中的表现都是指针,所以就是 heapOopSize 的值
_type2aelembytes[T_OBJECT] = heapOopSize;
_type2aelembytes[T_ARRAY] = heapOopSize;
}
void chunkpool_init() {
ChunkPool::initialize();
}
/*
* 将chunk分为4种大小
*/
static void initialize() {
// 为了满足各种内存大小的分配,分别按4种类型的大小创建chunk池,其实就是将Chunk组成一个链表,ChunkPool指向链表的表头
_large_pool = new ChunkPool(Chunk::size + Chunk::aligned_overhead_size());
_medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size());
_small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size());
_tiny_pool = new ChunkPool(Chunk::tiny_size + Chunk::aligned_overhead_size());
}
allocation.hpp中的定义的Chunk类
Chunk类是继承自CHeapObj类的,当new Chunk的时候也是通过CHeapObj类的new的实现完成的内存分配,由CHeapObj的名字可以看出,new分配内存时是在C堆内存下通过malloc系统调用函数分配的,注意,这里讲的是C堆,不是Java堆。
class Chunk: CHeapObj<mtChunk> {
friend class VMStructs;
protected:
Chunk* _next; // Next Chunk in list
const size_t _len; // Size of this Chunk
public:
void* operator new(size_t size, AllocFailType alloc_failmode, size_t length) throw();
void operator delete(void* p);
Chunk(size_t length);
enum {
// default sizes; make them slightly smaller than 2**k to guard against
// buddy-system style malloc implementations
#ifdef _LP64
slack = 40, // [RGV] Not sure if this is right, but make it
// a multiple of 8.
#else
slack = 20, // suspected sizeof(Chunk) + internal malloc headers
#endif
// 最小的chunk大小,slack就是chunk本身的大小,可以忽略这个slack占用的内存
tiny_size = 256 - slack, // Size of first chunk (tiny)
// 1k大小的chunk
init_size = 1*K - slack, // Size of first chunk (normal aka small)
// 10k大小的chunk
medium_size= 10*K - slack, // Size of medium-sized chunk
// 32k大小的chunk
size = 32*K - slack, // Default size of an Arena chunk (following the first)
// 1k + 32 字节大小的非池化的chunk大小
non_pool_size = init_size + 32 // An initial size which is not one of above
};
// 其他代码省略
}