[KANMARS原创] - (二) 从JVM源码来理解JVM内存的创建过程
以 UseSerialGC为例
JVM在创建堆结构时,会沿用如此堆栈顺序
Universe::initialize_heap() Universe对象初始化堆结构
代码: GenCollectorPolicy gc_policy = new MarkSweepPolicy(); 创建垃圾回收策略为标记清除垃圾回收对象
代码: Universe::_collectedHeap = new GenCollectedHeap(gc_policy); 创建堆为代回收堆
代码: Universe::heap()->initialize(); 堆初始化
1、创建垃圾回收策略为标记清除垃圾回收对象new MarkSweepPolicy()
initialize_all()
调用: initialize_flags(); 初始化一些标记,例如NewSize,MaxNewSize,PermSize,MaxPermSize,MinPermHeapExpansion,MaxPermHeapExpansion,MinHeapDeltaBytes,SharedReadOnlySize,SharedReadWriteSize,SharedMiscDataSize等
调用: initialize_size_info(); 初始化一些大小,例如min_gen0_size,initial_gen0_size,max_gen0_size等
调用: initialize_generations(); 初始化代信息
调用: initialize_perm_generation(PermGen::MarkSweepCompact); 初始化永久代信息
代码: _permanent_generation = new PermanentGenerationSpec(pgnm, PermSize, MaxPermSize, SharedReadOnlySize, SharedReadWriteSize, SharedMiscDataSize, SharedMiscCodeSize); 初始化永久代信息
代码: _generations = new GenerationSpecPtr[number_of_generations()]; 初始化特殊的代信息指针
代码: _generations[0] = new GenerationSpec(Generation::ParNew, _initial_gen0_size, _max_gen0_size); 并行回收的年轻代特殊对象
_generations[0] = new GenerationSpec(Generation::DefNew, _initial_gen0_size, _max_gen0_size); 普通的年轻代特殊对象
代码: _generations[1] = new GenerationSpec(Generation::MarkSweepCompact, _initial_gen1_size, _max_gen1_size); 标记清楚的代对象特殊对象
2、创建代回收堆,并设置垃圾回收策略为标记清除垃圾回收对象Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
调用构造方法: GenCollectedHeap(GenCollectorPolicy policy)
调用父类构造方法: SharedHeap(CollectorPolicy policy)
调用父类构造方法: CollectedHeap() 一些参数的设置
代码: const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT));
const size_t elements_per_word = HeapWordSize / sizeof(jint);
代码: if ((UseParNewGC ||(UseConcMarkSweepGC && CMSParallelRemarkEnabled) ||UseG1GC) &&ParallelGCThreads > 0) {
FlexibleWorkGang _workers = new FlexibleWorkGang(“Parallel GC Threads”, ParallelGCThreads,true,false);
}
_workers->initialize_workers();
代码: _gen_policy(policy),_gen_process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)),
3、对堆进行格式化Universe::heap()->initialize();
调用: GenCollectedHeap-::initialize();
调用: CollectedHeap::pre_initialize();
代码: _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store());
代码: char heap_address = allocate(alignment, perm_gen_spec, &total_reserved, &n_covered_regions, &heap_rs); 分配代内存,映射到指定位置
代码: total_reserved = _gen_specs[0]->max_size() + _gen_specs[1]->max_size() + perm_gen_spec->max_size() + perm_gen_spec->misc_data_size() + perm_gen_spec->misc_code_size(); 计算总可占用的最大内存大小
代码: _n_covered_regions = _gen_specs[0]->n_covered_regions() + _gen_specs[1]->n_covered_regions() + perm_gen_spec->n_covered_regions() 计算总可占用的最大内存分片数量
代码: char heap_address = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); 设置一些这样或者那样的属性
代码: ReservedSpace heap_rs = ReservedHeapSpace(total_reserved, alignment,UseLargePages, heap_address); 申请内存并创建到指定映射
调用父类构造函数: ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, char requested_address, const size_t noaccess_prefix)
调用函数: void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char requested_address,const size_t noaccess_prefix, bool executable)
代码: char base =os::reserve_memory(size, NULL, alignment); 申请内存并映射
调用: os::reserve_memory()
代码: return anon_mmap(requested_addr, bytes, (requested_addr != NULL));
代码: char addr = (char)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,flags, -1, 0); 调用原生Linux函数mmap,申请到一个可读可写的内存映射,大小为bytes
代码: char _base = addr;
代码: size_t _size = size;
代码: size_t _noaccess_prefix = prefix_align;
代码: size_t _alignment = noaccess_prefix;
调用: protect_noaccess_prefix(size)
调用父类函数: ReservedSpace::protect_noaccess_prefix(const size_t size) 对内存的起始位置进行调整
代码: _reserved = MemRegion((HeapWord)heap_rs.base(),(HeapWord)(heap_rs.base() + heap_rs.size())); 创造MemRegion内存分片对象
代码: HeapWord _start = start;
代码: size_t _word_size;
代码: _rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions); 创造原子性内存块集合
调用: CollectorPolicy::create_rem_set(MemRegion whole_heap,int max_covered_regions)
代码: CardTableRS res = new CardTableRS(whole_heap, max_covered_regions); 创造card table
调用父类构造函数: GenRemSet() // A GenRemSet provides ways of iterating over pointers accross generations.
内部全是虚函数,都在CardTableRS中实现
代码: _ct_bs = new CardTableModRefBSForCTRS(whole_heap, max_covered_regions);
调用父类构造函数: ModRefBarrierSet(max_covered_regions)
代码: _kind = BarrierSet::CardTableModRef
代码: HeapWord low_bound = _whole_heap.start();
代码: HeapWord high_bound = _whole_heap.end();
代码: MemRegion _covered = new MemRegion[max_covered_regions]; // The covered regions should be in address order.这个分片必须按内存地址进行排序
代码: MemRegion _committed = new MemRegion[max_covered_regions]; // The committed regions correspond one-to-one to the covered regions.这个是否已提交分片必须与covered regions一一对应
代码: MemRegion _guard_region = MemRegion((HeapWord)guard_page, _page_size);//The last card is a guard card, and we commit the page for it so
//we can use the card for verification purposes. We make sure we never
//uncommit the MemRegion for that page.
最后一个card是一个警戒card,我们能用这块内存来实现某种指定的意图,我们需要保证我们从不操作这块内存
代码: typedef jbyte CardPtr;
typedef CardPtr CardArr;
CardArr _lowest_non_clean = NEW_C_HEAP_ARRAY(CardArr, max_covered_regions);
size_t _lowest_non_clean_chunk_size = NEW_C_HEAP_ARRAY(size_t, max_covered_regions)
uintptr_t _lowest_non_clean_base_chunk_index = NEW_C_HEAP_ARRAY(uintptr_t, max_covered_regions)
int _last_LNC_resizing_collection = NEW_C_HEAP_ARRAY(int, max_covered_regions)
// This is an array, one element per covered region of the card table.
// Each entry is itself an array, with one element per chunk in the
// covered region. Each entry of these arrays is the lowest non-clean
// card of the corresponding chunk containing part of an object from the
// previous chunk, or else NULL.
英语很好懂,不解释。大意是每个array的元素是另一个array,每个二级array储存的是在当前region分片中的元素的chunk数组
因此,可知JVM内存分配中采用BarrierSet来对内存的每一个chunk进行管理
代码: set_bs(_ctbs);
代码: set_barrier_set(rem_set()->bs());
代码: _perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set());
调用: PermanentGenerationSpec::init(ReservedSpace rs,size_t init_size,GenRemSet *remset)
代码: ReservedSpace perm_rs = rs.first_part(_max_size, UseSharedSpaces,UseSharedSpaces); 获取到第一块可用的内存?
代码: ReservedSpace result(base(), partition_size, alignment, special(),executable());
代码; addr = os::attempt_reserve_memory_at(size, requested_address); 申请一块内存并放入ReservedSpace(此处与上处代码相同,走的是requested_address不为空的分支)
代码: ReservedSpace shared_rs = rs.last_part(_max_size); 申请获取最后一块内存(此处需要研究,在申请第一块和最后一块之后,是否中间的内存就全部申请完成)
代码: clear_incremental_collection_failed
至此内存代分配结束;