目录
2、ergo_initialize / global_initialize / post_initialize
在《Hotspot 内存管理之Metaspace(二) 源码解析》中讲解了负责Metaspace内存管理的VirtualSpaceList,ChunkManager,SpaceManager的实现,本篇博客重点讲解最外层的Metaspace的相关接口的实现。
一、Metaspace
1、定义
Metaspace的定义位于hotspot src/share/vm/memory/metaspace.hpp中,Metaspace表示用来给Klass等元数据分配内存的一个内存空间,通常称为元空间,每个ClassLoader实例包括启动类加载器都会创建一个对应的Metaspace实例,每个Metaspace实例都有一个SpaceManager实例,通过SpaceManager完成内存分配与管理。Metaspace定义的属性如下:
- static size_t _compressed_class_space_size; //compressed class对应的Metaspace大小
- static size_t _first_chunk_word_size; //第一个NonClassType类型的MetaChunk的大小
- static size_t _first_class_chunk_word_size; //第一个ClassType类型的MetaChunk的大小
- static size_t _commit_alignment; //commit内存的粒度
- static size_t _reserve_alignment; //reserve内存的粒度
- SpaceManager* _vsm; //NonClassType类型的元数据对应的SpaceManager
- SpaceManager* _class_vsm; //ClassType类型的元数据对应的SpaceManager
- static VirtualSpaceList* _space_list; // NonClassType类型的元数据对应的VirtualSpaceList
- static VirtualSpaceList* _class_space_list; // ClassType类型的元数据对应的VirtualSpaceList
- static ChunkManager* _chunk_manager_metadata; //NonClassType类型的元数据对应的ChunkManager
- static ChunkManager* _chunk_manager_class; // ClassType类型的元数据对应的ChunkManager
- static const MetaspaceTracer* _tracer; //打印日志使用
- AllocRecord * _alloc_record_head; //AllocRecord链表的头部元素
- AllocRecord * _alloc_record_tail; //AllocRecord链表的尾部元素
注意上述 ClassType类型的ChunkManager和VirtualSpaceList具体是指开启UseCompressedClassPointers下用来存储Class等元数据的元空间。
AllocRecord类的定义如下:
就是一个简单的记录内存分配结果的数据结构。重点关注以下方法的实现。
2、ergo_initialize / global_initialize / post_initialize
ergo_initialize、global_initialize、post_initialize这三个方法都是Metaspace的初始化方法,ergo_initialize用于初始化Metaspace的各种参数,如MetaspaceSize,MaxMetaspaceSize,MinMetaspaceExpansion等;global_initialize方法用于初始化_first_chunk_word_size,_space_list,_chunk_manager_metadata等静态属性;post_initialize就调用MetaspaceGC::post_initialize方法。各方法的调用链如下:
三个的源码实现如下,其中DumpSharedSpaces表示将共享的Metaspace空间dump到一个文件中,给其他JVM使用,默认为false;UseCompressedOops和UseCompressedClassPointers表示使用压缩的oop指针和Klass指针,64位下默认为true;UseSharedSpaces表示使用基于文件的共享Metaspace,即不同的JVM进程通过将Metaspace映射到同一个文件实现Metaspace共享,默认为false。
void Metaspace::ergo_initialize() {
if (DumpSharedSpaces) {
// Using large pages when dumping the shared archive is currently not implemented.
FLAG_SET_ERGO(bool, UseLargePagesInMetaspace, false);
}
size_t page_size = os::vm_page_size();
if (UseLargePages && UseLargePagesInMetaspace) {
page_size = os::large_page_size();
}
//初始化参数
_commit_alignment = page_size;
_reserve_alignment = MAX2(page_size, (size_t)os::vm_allocation_granularity());
MaxMetaspaceSize = align_size_down_bounded(MaxMetaspaceSize, _reserve_alignment);
if (MetaspaceSize > MaxMetaspaceSize) {
MetaspaceSize = MaxMetaspaceSize;
}
MetaspaceSize = align_size_down_bounded(MetaspaceSize, _commit_alignment);
assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize");
if (MetaspaceSize < 256*K) {
vm_exit_during_initialization("Too small initial Metaspace size");
}
MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment);
MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment);
CompressedClassSpaceSize = align_size_down_bounded(CompressedClassSpaceSize, _reserve_alignment);
set_compressed_class_space_size(CompressedClassSpaceSize);
//VIRTUALSPACEMULTIPLIER的值是2
uintx min_metaspace_sz =
VIRTUALSPACEMULTIPLIER * InitialBootClassLoaderMetaspaceSize;
if (UseCompressedClassPointers) {
if ((min_metaspace_sz + CompressedClassSpaceSize) > MaxMetaspaceSize) {
if (min_metaspace_sz >= MaxMetaspaceSize) {
vm_exit_during_initialization("MaxMetaspaceSize is too small.");
} else {
FLAG_SET_ERGO(uintx, CompressedClassSpaceSize,
MaxMetaspaceSize - min_metaspace_sz);
}
}
} else if (min_metaspace_sz >= MaxMetaspaceSize) {
FLAG_SET_ERGO(uintx, InitialBootClassLoaderMetaspaceSize,
min_metaspace_sz);
}
}
static void set_compressed_class_space_size(size_t size) {
_compressed_class_space_size = size;
}
void Metaspace::global_initialize() {
MetaspaceGC::initialize();
// Initialize the alignment for shared spaces.
int max_alignment = os::vm_allocation_granularity();
size_t cds_total = 0;
MetaspaceShared::set_max_alignment(max_alignment);
//DumpSharedSpaces默认为false
if (DumpSharedSpaces) {
#if INCLUDE_CDS
MetaspaceShared::estimate_regions_size();
SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment);
SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment);
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment);
// the min_misc_code_size e