本文是基于jdk11的hotspot源码进行分析的
堆是什么?
堆就是进程中的一段动态内存,在java中,一般会先申请一大段堆内存,然后mutatar在这一大段内存中进行分配。
活动对象: 能够通过gc root访问到的对象
g1创建堆入口
Universe::initialize_heap()
CollectedHeap* GCArguments::create_heap_with_policy() {
Policy* policy = new Policy();
policy->initialize_all();
return new Heap(policy);
}
创建G1CollectorPolicy对象
G1CollectorPolicy::G1CollectorPolicy() {
HeapRegion::setup_heap_region_size(InitialHeapSize, MaxHeapSize);
//Region初始化时,会初始化一个RSet,主要用来记录并跟踪其它Region指向该Region中对象的引用
HeapRegionRemSet::setup_remset_size();
}
initial_heap_size,初始化堆大小
max_heap_size: 最大堆大小
void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) {
size_t region_size = G1HeapRegionSize;
if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
size_t average_heap_size = (initial_heap_size + max_heap_size) / 2;
region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(),HeapRegionBounds::min_size());
}
// 计算region_size是2的幂次方,如果region_size=4*1024*1024,则region_size_log=22
int region_size_log = log2_long((jlong) region_size);
// Recalculate the region size to make sure it's a power of
// 2. This means that region_size is the largest power of 2 that's
// <= what we've calculated so far.
region_size = ((size_t)1 << region_size_log);
log_info(gc)("setup_heap region_size(M):" SIZE_FORMAT,region_size/1024/1024);
// Now make sure that we don't go over or under our limits.
if (region_size < HeapRegionBounds::min_size()) {
region_size = HeapRegionBounds::min_size();
} else if (region_size > HeapRegionBounds::max_size()) {
region_size = HeapRegionBounds::max_size();
}
// And recalculate the log. 算出region_size的lg值即2的几次方
region_size_log = log2_long((jlong) region_size);
// Now, set up the globals.
guarantee(LogOfHRGrainBytes == 0, "we should only set it once");
LogOfHRGrainBytes = region_size_log;
guarantee(LogOfHRGrainWords == 0, "we should only set it once");
//LogOfHRGrainWords=一个region的2次方再以8个字节对齐后的大小数
LogOfHRGrainWords = LogOfHRGrainBytes - LogHeapWordSize;
//算出一个region,占8个字节后,几次方
guarantee(GrainBytes == 0, "we should only set it once");
// The cast to int is safe, given that we've bounded region_size by
// MIN_REGION_SIZE and MAX_REGION_SIZE.
// 设置细粒度字节数为计算出来的分区大小(region_size)
GrainBytes = region_size;
log_info(gc, heap)("Heap region size: " SIZE_FORMAT "M", GrainBytes / M);
guarantee(GrainWords == 0, "we should only set it once");
//GrainWords=一个region再以8个字节对齐后的大小数
GrainWords = GrainBytes >> LogHeapWordSize; //一个region能容纳多少字节
guarantee((size_t) 1 << LogOfHRGrainWords == GrainWords, "sanity");
guarantee(CardsPerRegion == 0, "we should only set it once"); //G1CardTable::card_shift=2的9次方
CardsPerRegion = GrainBytes >> G1CardTable::card_shift;
//一个region有多少个卡页,card_shift占2的9次方=512,算出一个region有多少个卡面
log_info(gc, heap)("一个region 对应CardsPerRegion[卡页]: " SIZE_FORMAT , CardsPerRegion);
if (G1HeapRegionSize != GrainBytes) {
FLAG_SET_ERGO(size_t, G1HeapRegionSize, GrainBytes);
}
}
执行垃圾回收策略类对象的初始化:policy->initialize_all();
_space_alignment: 为了提高内存访问效率和遵循特定的内存对齐规则,需要确保空间按照一定的字节数进行对齐
卡表: JVM中用于记录内存引用关系的一种数据结构
void G1CollectorPolicy::initialize_alignments() {
// 空间对齐是1m
_space_alignment = HeapRegion::GrainBytes;
// 卡表对齐:卡表大小* os的page大小= 512 * 16 * 1024
size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint();
size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size();
_heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size);
}
进入到G1CollectedHeap的构造方法
G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* collector_policy) :
CollectedHeap(),
_young_gen_sampling_thread(NULL),
_collector_policy(collector_policy),
_soft_ref_policy(),
_card_table(NULL),
_memory_manager("G1 Young Generation", "end of minor GC"),
_full_gc_memory_manager("G1 Old Generation", "end of major GC"),
_eden_pool(NULL),
_survivor_pool(NULL),
_old_pool(NULL),
_gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()),
_gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()),
_g1_policy(new G1Policy(_gc_timer_stw)),
_collection_set(this, _g1_policy),
_dirty_card_queue_set(false),
_ref_processor_stw(NULL),
_is_alive_closure_stw(this),
_is_subject_to_discovery_stw(this),
_ref_processor_cm(NULL),
_is_alive_closure_cm(this),
_is_subject_to_discovery_cm(this),
_bot(NULL),
_hot_card_cache(NULL),
_g1_rem_set(NULL),
_cr(NULL),
_g1mm(NULL),
_preserved_marks_set(true /* in_c_heap */),
_old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()),
_humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()),
_humongous_reclaim_candidates(),
_has_humongous_reclaim_candidates(false),
_archive_allocator(NULL),
_summary_bytes_used(0),
_survivor_evac_stats("Young", YoungPLABSize, PLABWeight),
_old_evac_stats("Old", OldPLABSize, PLABWeight),
_expand_heap_after_alloc_failure(true),
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
_in_cset_fast_test() {
//初始化Gang工作线程
_workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
_verifier = new G1HeapVerifier(this);
//分配器
_allocator = new G1Allocator(this);
_heap_sizing_policy = G1HeapSizingPolicy::create(this, _g1_policy->analytics());
//HeapRegion::GrainWords=128,在G1垃圾收集器中,内存管理是以Region为单位的,假如region=1m,以8位对齐,那只有131072个words,大对象阈值就是占用一半
_humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords);
//在G1中,“humongous”对象是指那些大小超过一个或多个Heap Region容量一半的对象。这类大型对象会被特殊处理,因为它们太大而无法放入普通的Heap Region中。G1垃圾收集器会为这些大型对象分配专门的Humongous Region
// Override the default _filler_array_max_size so that no humongous filler
// objects are created. 覆盖默认的_filler_array_max_size,这样就不会创建庞大的填充对象
_filler_array_max_size = _humongous_object_threshold_in_words;
//并行gc数 RefToScanQueueSet扫描队列是管理需要被扫描和回收的对象引用
uint n_queues = ParallelGCThreads;
_task_queues = new RefToScanQueueSet(n_queues);
_evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
//为每个线程创建一个扫描队列
for (uint i = 0; i < n_queues; i++) {
RefToScanQueue* q = new RefToScanQueue();
q->initialize();
_task_queues->register_queue(i, q);
::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
}
// Initialize the G1EvacuationFailureALot counters and flags.初始化g1evacationfailurealot计数器和标志
NOT_PRODUCT(reset_evacuation_should_fail();)
_gc_tracer_stw->initialize();
guarantee(_task_queues != NULL, "task_queues allocation failure.");
}
jint status = _collectedHeap->initialize(); //执行初始化
jint G1CollectedHeap::initialize() {
os::enable_vtime();
size_t init_byte_size = collector_policy()->initial_heap_byte_size();
//G1GC 堆的最大大小
size_t max_byte_size = collector_policy()->max_heap_byte_size();
//g1gc 堆对齐为8192k
size_t heap_alignment = collector_policy()->heap_alignment();
// 返回ReservedHeapSpace对象,实际地申请VM堆,采用mmap方式,直接从操作系统中分配
ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size,heap_alignment);
//初始化,从基地址开始:0x7e8800000,这里申请256m,尾地址:0x7f8800000
initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size()));
// CardTable会映射到整个堆的空间,每个卡片会对应堆中的512B空间,在一个大小为1 GB的堆下,那么CardTable的长度为2097151 (1GB / 512B);每个Region 大小为1 MB,每个Region都会对应2048个Card Page
// Create the barrier set for the entire reserved region.G1CardTable 是实现并发标记(Concurrent Marking)和混合收集(Mixed Collections)等垃圾收集操作,创建全局卡表
// G1CardTable用于跟踪和记录哪些内存区域(或称为“卡片”,Cards)包含对其他区域有引用的对象,它通过维护一个卡片表来高效地管理这些卡片,使得垃圾收集器能够快速定位到哪些卡片可能包含跨区域引用
G1CardTable* ct = new G1CardTable(reserved_region());
ct->initialize(); //它将堆空间划分为一系列2次幂大小的卡页,记录堆内存中哪些“卡片”(堆内存的小块区域)包含跨代引用(年轻代对象引用老年代对象