根據《JVM垃圾回收》我們對垃圾收集器有個初步的概念.
相關模塊介紹
//VM_Operation
// VM_GC_Operation #是所有執行垃圾回收的VM_Operation的基類
// VM_CollectForAllocation #與其子類都是內存分配失敗觸發垃圾回收,然後嘗試分配內存的操作
// VM_GenCollectForAllocation
//表示一類在JVM線程中執行的操作,類似java中的任務
//hotspot/src/share/vm/runtime/vm_operations.hpp
class VM_Operation: public CHeapObj<mtInternal> {
enum Mode {
_safepoint, //表示執行此操作需要加鎖+安全點
_no_safepoint, //表示執行此操作需要加鎖
_concurrent, //無需要任務條件
_async_safepoint //表示執行此操作需要安全點
};
//具體執行VM_Operation的方法,通過evaluate方法調用,子類不能改寫evaluate方法的實現
doit:
//用於執行準備工作,當Java線程調用VMThread::execute((VM_Operation*)執行某個VM_Operation時會先執行doit_prologue如果該方法返回true纔會執行evaluate方法,否則被取消不執行。
doit_prologue
//用於執行某些依賴於VM_Operation執行結果的動作,當VM_Operation執行完成,Java線程會調用doit_epilogue方法一次。
doit_epilogue
}
//表示一個特殊的專門用來執行比較耗時的VM_Operation的原生線程
//hotspot/src/share/vm/runtime/vMThread.hpp
class VMThread {
//當前執行的VM operation
static VM_Operation* _cur_vm_operation;
// 緩存待執行的VM operation 隊列
static VMOperationQueue* _vm_queue;
void VMThread::create() {
//創建VMThread線程,及VMOperationQueue隊列
}
void VMThread::execute(VM_Operation* op) {
//用於執行某個VM_Operation,execute方法會先執行doit_prologue,該方法執行成功後將該操作放入一個等待隊列中,然後等待VMThread執行該操作完成,最後再執行doit_epilogue
}
void VMThread::run() {
//其中loop方法執行的核心業務邏輯了,該方法不斷從待執行的VM Operation隊列_vm_queue中獲取待執行的VM_Operation實例,然後調用其evaluate方法
}
}
//描述分代參數的一個類
//hotspot/src/share/vm/memory/generationSpec.hpp
class GenerationSpec : public CHeapObj<mtGC> {
Generation::Name _name;//分代名
size_t _init_size;//初始大步
size_t _max_size;//最大大小
// 返回這個分代所需要的 remembered set 空間.
virtual int n_covered_regions() const { return 1; }
//創建分帶代
Generation* GenerationSpec::init(ReservedSpace rs, int level,
GenRemSet* remset) {
switch (name()) {
case Generation::DefNew:
return new DefNewGeneration(rs, init_size(), level);
case Generation::MarkSweepCompact:
return new TenuredGeneration(rs, init_size(), level, remset);
case Generation::ParNew:
return new ParNewGeneration(rs, init_size(), level);
case Generation::ASParNew:
return new ASParNewGeneration(rs,init_size(),init_size() ,level);
case Generation::ConcurrentMarkSweep: {
assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set");
CardTableRS* ctrs = remset->as_CardTableRS();
if (ctrs == NULL) {
vm_exit_during_initialization("Rem set incompatibility.");
}
// Otherwise
// The constructor creates the CMSCollector if needed,
// else registers with an existing CMSCollector
ConcurrentMarkSweepGeneration* g = NULL;
g = new ConcurrentMarkSweepGeneration(rs,
init_size(), level, ctrs, UseCMSAdaptiveFreeLists,
(FreeBlockDictionary<FreeChunk>::DictionaryChoice)CMSDictionaryChoice);
g->initialize_performance_counters();
return g;
}
case Generation::ASConcurrentMarkSweep: {
//...
}
default:
guarantee(false, "unrecognized GenerationName");
return NULL;
}
}
}
//用來記錄不同分代年齡的對象的大小,然後據此動態調整tenuring_threshold
//hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp
class ageTable {
enum { table_size = markOopDesc::max_age + 1 };
//sizes就是保存不同分代年齡的對象的大小的數組
size_t sizes[table_size];
//所對象存進行
//如果想取1歲對象佔分代的大小,就直接sizes[1]
void add(oop p, size_t oop_size) {
add(p->age(), oop_size);
}
void add(uint age, size_t oop_size) {
sizes[age] += oop_size;
}
//傳一個的survivor_capacity值,根據ageTable的數據,把對象重新畫區
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity)
}
//Space及其子類是Generation中用於內存分配管理的底層實現
//hotspot/src/share/vm/memory/space.hpp
class Space: public CHeapObj<mtGC> {
//內存區域的起始地址
HeapWord* _bottom;
//內存區域的終止地址
HeapWord* _end;
// 用來遍歷Space內的MemRegion
MemRegionClosure* _preconsumptionDirtyCardClosure;
}
//增加了壓縮操作的支持,即在垃圾回收後通過複製移動Java對象的位置減少Space內部的內存空洞和碎片問題,提升內存利用率
//hotspot/src/share/vm/memory/space.hpp
class CompactibleSpace: public Space {
}
//表示一個空閒內存空間是地址連續的Space,從而支持快速的內存分配和壓縮
//hotspot/src/share/vm/memory/space.hpp
class ContiguousSpace: public CompactibleSpace {
//bottom到top之間的內存都是已經被分配出去的內存
HeapWord* _top;
//從bottom到_concurrent_iteration_safe_limit之間的對象都被認爲是已經初始化完成的對象,對於object_iterate_careful方法可以安全遍歷的,該屬性在初始化時通常設置爲bottom,在compact結束後設置爲compact_top。
HeapWord* _concurrent_iteration_safe_limit;
//負責對Space執行mangle的輔助類
GenSpaceMangler* _mangler;
}
//用來表示Eden區
class EdenSpace : public ContiguousSpace {
//關聯的年輕代DefNewGeneration實例
DefNewGeneration* _gen;
//分配內存的一個軟限制, 當達到了這個限制後,慢速分配的代碼可以執行其他的邏輯,然後調整_soft_end到一個新的限制或者end()
HeapWord* _soft_end;
}
// CollectedHeap
// SharedHeap 分層的堆基類
// GenCollectedHeap 普通分帶法
// G1CollectedHeap G1分帶法
// ParallelScavengeHeap ps分帶及策略
//一個抽象類,表示一個Java堆,定義了各種垃圾回收算法必須實現的公共接口,這些接口就是上層類用來分配Java對象,分配TLAB,獲取Java堆使用情況等的統一API
//hotspot/src/share/vm/gc_interface/collectedHeap.hpp
class CollectedHeap : public CHeapObj<mtInternal> {
//填充數組的最大值
static size_t _filler_array_max_size;
//用來打印GC日誌
GCHeapLog* _gc_heap_log;
//開啓C2編譯時使用,支持ReduceInitialCardMarks
bool _defer_initial_card_mark;
//Java堆對應的一段連續內存空間
MemRegion _reserved;
//卡表(CardTable)的基類
//BarrierSet的功能類似於一個攔截器,在讀寫動作實際作用於內存前執行某些前置或者後置動作
BarrierSet* _barrier_set;
//是否正在執行GC
bool _is_gc_active;
//並行執行GC任務的線程數
uint _n_par_threads;
//從JVM啓動至今的GC次數
unsigned int _total_collections;
//從JVM啓動至今的Full GC次數
unsigned int _total_full_collections;
//當前GC被觸發的原因,Cause是GCCause定義的枚舉
GCCause::Cause _gc_cause;
//上一次GC被觸發的原因
GCCause::Cause _gc_lastcause;
//開啓UsePerfData時用來保存_gc_cause
PerfStringVariable* _perf_gc_cause;
//開啓UsePerfData時用來保存_gc_lastcause
PerfStringVariable* _perf_gc_lastcause;
}
//hotspot/src/share/vm/memory/sharedHeap.hpp
class SharedHeap : public CollectedHeap {
//靜態SharedHeap實例,單例
static SharedHeap* _sh;
// the Gen Remembered Set,卡表實現
GenRemSet* _rem_set;
//垃圾回收策略
CollectorPolicy *_collector_policy;
//遍歷Java線程包含的oop使用的
int _strong_roots_parity;
//執行並行GC(parallel GC)的線程池
FlexibleWorkGang* _workers;
//SharedHeap構造
SharedHeap::SharedHeap(CollectorPolicy* policy_) :
CollectedHeap(),
_collector_policy(policy_),
_rem_set(NULL),
_strong_roots_parity(0),
_workers(NULL)
{
//初始化靜態屬性_sh
_sh = this; // ch is static, should be set only once.
if ((UseParNewGC ||
(UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled ||
CMSParallelRemarkEnabled)) ||
UseG1GC) &&
ParallelGCThreads > 0) {
//初始化執行並行GC的線程池
_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
if (_workers == NULL) {
vm_exit_during_initialization("Failed necessary allocation.");
} else {
_workers->initialize_workers();
}
}
}
}
//heap具體的分帶實現
//hotspot/src/share/vm/memory/genCollectedHeap.hpp
class GenCollectedHeap : public SharedHeap {
//靜態GenCollectedHeap實例,單例
static GenCollectedHeap* _gch;
//包含的Generation的個數,通常是2(老年代,年輕帶)
int _n_gens;
//Generation數組,分代的具體指針
Generation* _gens[max_gens];
//GenerationSpec主要用來存儲各分帶的創建數據
GenerationSpec** _gen_specs;
//垃圾回收策略
GenCollectorPolicy* _gen_policy;
//執行promote是否會失敗
bool _incremental_collection_failed;
//已經執行萬恆的Full GC的次數
unsigned int _full_collections_completed;
//用於控制根節點遍歷任務的並行執行
SubTasksDone* _process_strong_tasks;
//GenCollectedHeap構造
GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :
SharedHeap(policy),
_gen_policy(policy),
_process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)),
_full_collections_completed(0)
{
assert(policy != NULL, "Sanity check");
}
jint GenCollectedHeap::initialize() {
CollectedHeap::pre_initialize();
int i;
//_n_gens表示有多少代,通常是2代,年輕代和老年代
_n_gens = gen_policy()->number_of_generations();
guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");
size_t gen_alignment = Generation::GenGrain;
//拿出堆模型數據
_gen_specs = gen_policy()->generations();
for (i = 0; i < _n_gens; i++) {
//將內存的初始值和最大值按照內存分配粒度對齊
_gen_specs[i]->align(gen_alignment);
}
char* heap_address;
size_t total_reserved = 0;
int n_covered_regions = 0;
ReservedSpace heap_rs;
size_t heap_alignment = collector_policy()->heap_alignment();
//根據各GenerationSpec的最大大小計算總的需要保留的內存空間,然後申請指定大小的連續內存空間
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs);
if (!heap_rs.is_reserved()) {
//申請失敗
vm_shutdown_during_initialization(
"Could not reserve enough space for object heap");
return JNI_ENOMEM;
}
//設置_reserved相關屬性
_reserved = MemRegion((HeapWord*)heap_rs.base(),
(HeapWord*)(heap_rs.base() + heap_rs.size()));
_reserved.set_word_size(0);
_reserved.set_start((HeapWord*)heap_rs.base());
size_t actual_heap_size = heap_rs.size();
_reserved.set_end((HeapWord*)(heap_rs.base() + actual_heap_size));
//collector_policy()和gen_policy()表示相同變量
//根據各區域名需要的_rem_set區域,初始化GenRemSet
_rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions);
set_barrier_set(rem_set()->bs());
_gch = this;
//初始化各Generation
for (i = 0; i < _n_gens; i++) {
//提取出max_size的內存
ReservedSpace this_rs = heap_rs.first_part(_gen_specs[i]->max_size(), false, false);
//使用提取出的,內存和卡表引出,創建初始化分代
_gens[i] = _gen_specs[i]->init(this_rs, i, rem_set());
//將下次內存指針向下移max_size
heap_rs = heap_rs.last_part(_gen_specs[i]->max_size());
}
//將_incremental_collection_failed置爲false
clear_incremental_collection_failed();
#if INCLUDE_ALL_GCS
if (collector_policy()->is_concurrent_mark_sweep_policy()) {
//如果是CMS則創建CMSCollector
bool success = create_cms_collector();
if (!success) return JNI_ENOMEM;
}
#endif // INCLUDE_ALL_GCS
return JNI_OK;
}
char* GenCollectedHeap::allocate(size_t alignment,
size_t* _total_reserved,
int* _n_covered_regions,
ReservedSpace* heap_rs){
const char overflow_msg[] = "The size of the object heap + VM data exceeds "
"the maximum representable size";
// Now figure out the total size.
size_t total_reserved = 0;
int n_covered_regions = 0;
const size_t pageSize = UseLargePages ?
os::large_page_size() : os::vm_page_size();
assert(alignment % pageSize == 0, "Must be");
//遍歷所有的_gen_specs,累加各GenerationSpec的max_size和n_covered_regions
for (int i = 0; i < _n_gens; i++) {
total_reserved += _gen_specs[i]->max_size();
if (total_reserved < _gen_specs[i]->max_size()) {
vm_exit_during_initialization(overflow_msg);
}
n_covered_regions += _gen_specs[i]->n_covered_regions();
}
//校驗累加後的total_reserved已經是內存對齊的
assert(total_reserved % alignment == 0,
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="
SIZE_FORMAT, total_reserved, alignment));
//加2是爲卡表保留的
n_covered_regions += 2;
//賦值
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
//申請指定大小的連續內存空間
*heap_rs = Universe::reserve_heap(total_reserved, alignment);
//返回基地址
return heap_rs->base();
}
//執行垃圾回收的核心方法,其底層核心就是各Genaration的collect方法
void GenCollectedHeap::do_collection(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab,
int max_level) {
bool prepared_for_verification = false;
ResourceMark rm;
//校驗處於安全點上
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
//校驗調用線程是VMThread 或者CMS Thread
assert(my_thread->is_VM_thread() ||
my_thread->is_ConcurrentGC_thread(),
"incorrect thread type capability");
//校驗獲取了Heap_lock鎖
assert(Heap_lock->is_locked(),
"the requesting thread should have the Heap_lock");
guarantee(!is_gc_active(), "collection is not reentrant");
assert(max_level < n_gens(), "sanity check");
//檢查是否有線程處於JNI關鍵區,check_active_before_gc返回true表示有,則終止當前GC,等待線程退出
//最後一個退出的線程會負責執行GC
if (GC_locker::check_active_before_gc()) {
return;
}
//是否需要清除軟引用
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
collector_policy()->should_clear_all_soft_refs();
//ClearedAllSoftRefs通過析構函數設置CollectorPolicy的_all_soft_refs_clear屬性
ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
//獲取元空間已使用內存
const size_t metadata_prev_used = MetaspaceAux::used_bytes();
//打印GC的堆內存使用情況
print_heap_before_gc();
{
//臨時設置_is_gc_active爲true,表示GC開始了
FlagSetting fl(_is_gc_active, true);
bool complete = full && (max_level == (n_gens()-1));
const char* gc_cause_prefix = complete ? "Full GC" : "GC";
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL, GCId::peek());
//遍歷各Generation執行GC準備工作
gc_prologue(complete);
//增加GC次數
increment_total_collections(complete);
//統計總的內存使用量
size_t gch_prev_used = used();
int starting_level = 0;
if (full) {
//如果老年代設置了full Gc要先收集年輕代的話
//full_collects_younger_generations = false
//否則爲true,starting_level=1
for (int i = max_level; i >= 0; i--) {
if (_gens[i]->full_collects_younger_generations()) {
starting_level = i;
break;
}
}
}
bool must_restore_marks_for_biased_locking = false;
int max_level_collected = starting_level;
for (int i = starting_level; i <= max_level; i++) {
if (_gens[i]->should_collect(full, size, is_tlab)) {
//如果需要垃圾回收
if (i == n_gens() - 1) { // a major collection is to happen
//如果是老年代
if (!complete) {
//increment_total_collections方法只有在complete爲true時纔會增加_total_full_collections計數
//此處complete爲false,但還是老年代的GC,所以增加計數
increment_total_full_collections();
}
//根據參數配置dump
pre_full_gc_dump(NULL); // do any pre full gc dumps
}
GCTraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, NULL, GCId::peek());
TraceCollectorStats tcs(_gens[i]->counters());
TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause());
size_t prev_used = _gens[i]->used();
//增加計數
_gens[i]->stat_record()->invocations++;
_gens[i]->stat_record()->accumulated_time.start();
//記錄各Generation的Space的top指針,生產版本爲空實現
record_gen_tops_before_GC();
if (PrintGC && Verbose) {
gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
i,
_gens[i]->stat_record()->invocations,
size*HeapWordSize);
}
if (VerifyBeforeGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
if (!prepared_for_verification) {
prepare_for_verify();
prepared_for_verification = true;
}
Universe::verify(" VerifyBeforeGC:");
}
COMPILER2_PRESENT(DerivedPointerTable::clear());
if (!must_restore_marks_for_biased_locking &&
//DefNewGeneration返回false,ConcurrentMarkSweepGeneration採用父類默認實現返回true
_gens[i]->performs_in_place_marking()) {
must_restore_marks_for_biased_locking = true;
//將各線程的持有偏向鎖的oop的對象頭保存起來
BiasedLocking::preserve_marks();
}
// Do collection work
{
HandleMark hm; // Discard invalid handles created during gc
save_marks(); // save marks for all gens
ReferenceProcessor* rp = _gens[i]->ref_processor();
if (rp->discovery_is_atomic()) {
rp->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
rp->setup_policy(do_clear_all_soft_refs);
} else {
//collect方法會調用enable_discovery方法
}
//執行垃圾回收
_gens[i]->collect(full, do_clear_all_soft_refs, size, is_tlab);
if (!rp->enqueuing_is_done()) {
//enqueuing_is_done爲false
//將處理後剩餘的References實例加入到pending-list中
rp->enqueue_discovered_references();
} else {
//enqueuing_is_done爲true,已經加入到pending-list中了,將其恢復成默認值
rp->set_enqueuing_is_done(false);
}
rp->verify_no_references_recorded();
}
max_level_collected = i;
// Determine if allocation request was met.
if (size > 0) {
if (!is_tlab || _gens[i]->supports_tlab_allocation()) {
if (size*HeapWordSize <= _gens[i]->unsafe_max_alloc_nogc()) {
size = 0;
}
}
}
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
_gens[i]->stat_record()->accumulated_time.stop();
//更新各Generation的GC統計信息
update_gc_stats(i, full);
if (VerifyAfterGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
Universe::verify(" VerifyAfterGC:");
}
if (PrintGCDetails) {
gclog_or_tty->print(":");
_gens[i]->print_heap_change(prev_used);
}
}
}//for循環結束
//是否Full GC
complete = complete || (max_level_collected == n_gens() - 1);
if (complete) { // We did a "major" collection
//根據配置dump
post_full_gc_dump(NULL); // do any post full gc dumps
}
if (PrintGCDetails) {
print_heap_change(gch_prev_used);
if (complete) {
MetaspaceAux::print_metaspace_change(metadata_prev_used);
}
}
for (int j = max_level_collected; j >= 0; j -= 1) {
//調整各Generation的容量
_gens[j]->compute_new_size();
}
if (complete) {
//刪掉被卸載的ClassLoader實例及其相關元數據
ClassLoaderDataGraph::purge();
MetaspaceAux::verify_metrics();
//重置元空間大小
MetaspaceGC::compute_new_size();
update_full_collections_completed();
}
//跟蹤GC後的內存使用
MemoryService::track_memory_usage();
gc_epilogue(complete);
if (must_restore_marks_for_biased_locking) {
BiasedLocking::restore_marks();
}
}
AdaptiveSizePolicy* sp = gen_policy()->size_policy();
AdaptiveSizePolicyOutput(sp, total_collections());
print_heap_after_gc();
}
//DefNewGeneration採用父類Generation的默認實現,返回false
//ConcurrentMarkSweepGeneration的實現如下
//UseCMSCompactAtFullCollection默認爲true,表示FullGC時所使用Mark-Sweep-Compact算法
//CollectGen0First默認爲false,表示是否在FullGC前收集年輕代
virtual bool full_collects_younger_generations() const {
return UseCMSCompactAtFullCollection && !CollectGen0First;
}
}
// Generation
// CardGeneration
// ConcurrentMarkSweep #cms
// ASConcurrentMarkSweep # 自適應cms
// OneContigSpaceCardGeneration
// TenuredGeneration
// DefNewGeneration
// ParNewGeneration
// ASParNewGeneration
//CMS算法使用的表示年輕代的DefNewGeneration和表示支持自適應調整堆內存大小的老年代的ASConcurrentMarkSweepGeneration類
//表示分代內存中的一個“代”對應的內存區域,是各種分代內存實現的抽象類
//hotspot/src/share/vm/memory/generation.hpp
class Generation: public CHeapObj<mtGC> {
//記錄上一次GC的發生時間
jlong _time_of_last_gc;
//在GC過程中的某個特殊時點使用的,用於記錄某個值
MemRegion _prev_used_region;
//爲當前Generation保留的一段連續的內存地址空間,注意不能跟其他的Generation的地址空間有交叉
MemRegion _reserved;
// Memory area reserved for generation
VirtualSpace _virtual_space;
//當前Generation在類繼承關係中的級別
int _level;
//用於處理Reference實例的處理器
ReferenceProcessor* _ref_processor;
//用於GC性能跟蹤
CollectorCounters* _gc_counters;
//收集GC的統計數據
GCStats* _gc_stats;
//Generation定義了一個枚舉Name來描述各子類,其定義如下:
enum Name {
ASParNew,
ASConcurrentMarkSweep,
DefNew,
ParNew,
MarkSweepCompact,(對應繼承類TenuredGeneration)
ConcurrentMarkSweep,
Other
};
//默認種類返回
virtual Generation::Name kind() { return Generation::Other;}
//是否要收集
//如果full爲true,強制收集
//否則判斷空間是否充足
virtual bool should_collect(bool full,
size_t word_size,
bool is_tlab) {
return (full || should_allocate(word_size, is_tlab));
}
}
//表示一個使用卡表來標記對象修改
//hotspot/src/share/vm/memory/generation.hpp
class CardGeneration: public Generation {
//與其他Generation實例共享的卡表實現實例(指向SharedHeap中的)
GenRemSet* _rs;
//當前Generation獨享的BlockOffsetArray實現
//記錄內存塊的起始位置
BlockOffsetSharedArray* _bts;
//老年代內存縮容的百分比,第一次是0,第二次是10,第三次是40,第四次是100,中間有一次擴容了則被重置爲0,重新開始累加,避免頻繁的縮容與擴容。
size_t _shrink_factor;
//老年代內存擴展或者縮容時的最低內存值
size_t _min_heap_delta_bytes;
//GC開始時的內存容量
size_t _capacity_at_prologue;
//GC開始時的內存使用量
size_t _used_at_prologue;
}
//表示CMS的老年代
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
class ConcurrentMarkSweepGeneration: public CardGeneration {
//封裝了老年代垃圾回收的相關屬性和實現邏輯
static CMSCollector* _collector;
//老年代對應的Space實現
CompactibleFreeListSpace* _cmsSpace;
//直接從老年代分配而非promote時間接分配的內存的大小,是一個累加值,CMSStats使用的
size_t _direct_allocated_words;
//是否增量收集失敗
bool _incremental_collection_failed;
//實際是一個CMSParGCThreadState指針數組,元素個數就是ParallelGCThreads,即並行GC的線程數,CMSParGCThreadState是執行老年代promote時使用的
CMSParGCThreadState** _par_gc_thread_states;
//老年代擴展的原因,shouldConcurrentCollect()方法據此判斷是否應該GC
CMSExpansionCause::Cause _expansion_cause;
//是否完成壓縮
bool _did_compact;
//觸發老年代GC的內存佔用百分比,是一個兩位的小數
double _initiating_occupancy;
//UseCMSCompactAtFullCollection默認爲true,表示FullGC時所使用Mark-Sweep-Compact算法
//CollectGen0First默認爲false,表示是否在FullGC前收集年輕代
virtual bool full_collects_younger_generations() const {
return UseCMSCompactAtFullCollection && !CollectGen0First;
}
}
//表示年輕代,包括(den, from- and to-space.)
//hotspot/src/share/vm/memory/defNewGeneration.hpp
class DefNewGeneration: public Generation {
//對老年代的引用,初始化時爲null,第一次GC時會賦值
Generation* _next_gen;
//將對象拷貝到老年代的分代年齡閾值,大於該值拷貝到老年代,否則拷貝到to區,該值在初始化時賦值成參數MaxTenuringThreshold,默認是15;每次GC結束後都會通過ageTable調整。
uint _tenuring_threshold;
//記錄不同分代年齡的對象的總大小
ageTable _age_table;
//表示年輕代中允許分配的對象的最大字寬數,默認是0,即無限制
size_t _pretenure_size_threshold_words;
//真實地址大內存在ReservedSpace已經外面
//用EdenSpace與ContiguousSpace等類,標識已計算出給年代代的東西
//barrier_set也得新高監聽區域
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
int level,
const char* policy)
: Generation(rs, initial_size, level),
_promo_failure_drain_in_progress(false),
_should_allocate_from_space(false)
{
MemRegion cmr((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
//重置bs對應的內存區域
Universe::heap()->barrier_set()->resize_covered_region(cmr);
//has_soft_ended_eden方法的返回值取決於屬性CMSIncrementalMode,默認爲false
//初始化三個內存區域
if (GenCollectedHeap::heap()->collector_policy()->has_soft_ended_eden()) {
_eden_space = new ConcEdenSpace(this);
} else {
_eden_space = new EdenSpace(this);
}
_from_space = new ContiguousSpace();
_to_space = new ContiguousSpace();
if (_eden_space == NULL || _from_space == NULL || _to_space == NULL)
vm_exit_during_initialization("Could not allocate a new gen space");
//計算survivor區和eden區的最大空間,即年輕代最大內存時survivor區和eden區的內存空間
uintx alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment();
uintx size = _virtual_space.reserved_size();
_max_survivor_size = compute_survivor_size(size, alignment);
_max_eden_size = size - (2*_max_survivor_size);
//計算三個內存區的大小和邊界,並初始化
compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
//...
}
HeapWord* DefNewGeneration::allocate(size_t word_size,
bool is_tlab) {
//正常情況下只有慢速分配對象時纔會進入此方法,此時在GenCollectHeap層已經獲取了鎖
//par_allocate不要求調用方獲取全局鎖,底層使用cmpxchg原子指令,更快
HeapWord* result = eden()->par_allocate(word_size);
if (result != NULL) {
//如果分配成功
//CMSEdenChunksRecordAlways表示是否記錄eden區分配的內存塊,默認爲true
if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
_next_gen->sample_eden_chunk();
}
return result;
}
do {
HeapWord* old_limit = eden()->soft_end();
if (old_limit < eden()->end()) {
//通知老年代,年輕代已經達到了分配限制soft_end,老年代會返回一個新的限制
//非iCMS模式下,該方法就是返回NULL,就end和soft_end一直
HeapWord* new_limit =
next_gen()->allocation_limit_reached(eden(), eden()->top(), word_size);
if (new_limit != NULL) {
//原子的修改eden區的soft_end屬性
Atomic::cmpxchg_ptr(new_limit, eden()->soft_end_addr(), old_limit);
} else {
assert(eden()->soft_end() == eden()->end(),
"invalid state after allocation_limit_reached returned null");
}
} else {
//soft_end跟end一致了,必須擴容才能繼續分配,終止循環
assert(old_limit == eden()->end(), "sanity check");
break;
}
//再次嘗試分配,直到分配成功或者soft_end跟end一致
result = eden()->par_allocate(word_size);
} while (result == NULL);
if (result == NULL) {
//從from區域分配內存
result = allocate_from_space(word_size);
} else if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
//while循環重試分配成功
_next_gen->sample_eden_chunk();
}
return result;
}
//此方法的四個參數只有clear_all_soft_refs是有用的參數,如果爲true表示會清除所有的軟引用
//如果是false則按照默認邏輯處理
void DefNewGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
assert(full || size > 0, "otherwise we don't want to collect");
GenCollectedHeap* gch = GenCollectedHeap::heap();
//記錄GC的開始時間和原因
//...
//老年代
_next_gen = gch->next_gen(this);
//判斷老年代是否有足夠的空間保存年輕代複製過去的對象
if (!collection_attempt_is_safe()) {
//通知GCH老年代空間不足
gch->set_incremental_collection_failed(); // Slight lie: we did not even attempt one
//老年代空間不足,終止年輕代的GC
return;
}
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
//將_promotion_failed屬性置爲false,記錄promote失敗信息的PromotionFailedInfo重置成初始狀態
init_assuming_no_promotion_failure();
GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, gc_tracer.gc_id());
// Capture heap used before collection (for printing).
size_t gch_prev_used = gch->used();
//設置GC Tracer
gch->trace_heap_before_gc(&gc_tracer);
SpecializationStats::clear();
//初始化兩個遍歷器
IsAliveClosure is_alive(this);
ScanWeakRefClosure scan_weak_ref(this);
//重置ageTable
age_table()->clear();
//重置to區
to()->clear(SpaceDecorator::Mangle);
//重置cur_youngergen_card_val,並行遍歷髒的卡表項時使用
gch->rem_set()->prepare_for_younger_refs_iterate(false);
assert(gch->no_allocs_since_save_marks(0),
"save marks have not been newly set.");
CollectorPolicy* cp = gch->collector_policy();
//FastScanClosure用來遍歷年輕代中的存活對象oop,第二個參數爲true,表示會將oop對應的卡表項置爲youngergen_card
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
//KlassScanClosure用來遍歷在上一次GC到當前GC之間創建的新的Klass對應的Class實例
KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier,
gch->rem_set()->klass_rem_set());
//CLDToKlassAndOopClosure用來遍歷一個ClassLoader加載的所有類對應的Class實例和依賴等
CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
&fsc_with_no_gc_barrier,
false);
//設置promote失敗時的遍歷器
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
//FastEvacuateFollowersClosure主要用來遍歷被promote到老年代的對象,恢復其對象頭並遍歷其引用類型屬性
FastEvacuateFollowersClosure evacuate_followers(gch, _level, this,
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier);
assert(gch->no_allocs_since_save_marks(0),
"save marks have not been newly set.");
//執行根節點遍歷以及老年代新應用的oop遍歷
gch->gen_process_roots(_level, //level就是0
true, //因爲level是0,所以此參數實際無意義
true, // StrongRootsScope的active入參爲true
GenCollectedHeap::SO_ScavengeCodeCache, //只遍歷nmethod中的oop
GenCollectedHeap::StrongAndWeakRoots,//StrongAndWeakRoots是靜態常量,值爲false,表示會遍歷weak root,如StringTable中的String對象
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier,
&cld_scan_closure);
//遍歷所有promote到老年代的對象,恢復其對象頭,遍歷其引用類型屬性
evacuate_followers.do_void();
FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
ReferenceProcessor* rp = ref_processor();
rp->setup_policy(clear_all_soft_refs);
//處理do_void方法遍歷引用類型屬性過程中找到的Reference實例,如果該實例的referent對象是存活的,則從待處理列表中移除,否則將referent屬性置爲null
const ReferenceProcessorStats& stats =
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
NULL, _gc_timer, gc_tracer.gc_id());
gc_tracer.report_gc_reference_stats(stats);
if (!_promotion_failed) {
//promote沒有失敗的
//重置清空eden區和from區
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
if (ZapUnusedHeapArea) {
to()->mangle_unused_area();
}
//交換from區和to區
swap_spaces();
//交換後,原來的from區變成to區,必須是空的
assert(to()->is_empty(), "to space should be empty now");
//調整tenuring_threshold
adjust_desired_tenuring_threshold();
AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
//重置gc_overhead_limit_count
size_policy->reset_gc_overhead_limit_count();
if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used);
}
assert(!gch->incremental_collection_failed(), "Should be clear");
} else {
//如果存在promote失敗的情形
assert(_promo_failure_scan_stack.is_empty(), "post condition");
//drain_promo_failure_scan_stack方法會負責處理掉裏面保存的oop,遍歷其所引用的其他oop,找到的oop的處理邏輯就是fsc_with_no_gc_barrier
//釋放_promo_failure_scan_stack的內存,
_promo_failure_scan_stack.clear(true); // Clear cached segments.
//移除from區和eden區包含的對象的froward指針
remove_forwarding_pointers();
if (PrintGCDetails) {
gclog_or_tty->print(" (promotion failed) ");
}
//交換from區和to區,注意此時eden區和from區因爲promote失敗所以不是空的,還有存活對象
swap_spaces(); // For uniformity wrt ParNewGeneration.
//將to區作爲from區的next_compaction_space,正常爲NULL
from()->set_next_compaction_space(to());
//將incremental_collection_failed置爲true
gch->set_incremental_collection_failed();
//通知老年代promote失敗,CMS老年代實際不做處理
_next_gen->promotion_failure_occurred();
gc_tracer.report_promotion_failed(_promotion_failed_info);
}
//設置並行遍歷時的邊界
from()->set_concurrent_iteration_safe_limit(from()->top());
to()->set_concurrent_iteration_safe_limit(to()->top());
SpecializationStats::print();
//更新GC完成時間
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
gch->trace_heap_after_gc(&gc_tracer);
gc_tracer.report_tenuring_threshold(tenuring_threshold());
_gc_timer->register_gc_end();
//更新GC日誌
gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
}
oop DefNewGeneration::copy_to_survivor_space(oop old) {
assert(is_in_reserved(old) && !old->is_forwarded(),
"shouldn't be scavenging this oop");
size_t s = old->size();
oop obj = NULL;
// Try allocating obj in to-space (unless too old)
if (old->age() < tenuring_threshold()) {
//如果對象的年齡低於tenuring_threshold,則該在to區申請一塊同樣大小的內存
obj = (oop) to()->allocate_aligned(s);
}
// Otherwise try allocating obj tenured
if (obj == NULL) {
//如果如果對象的年齡大於tenuring_threshold或者to區申請內存失敗
//則嘗試將該對象複製到老年代
obj = _next_gen->promote(old, s);
if (obj == NULL) {
//複製失敗
handle_promotion_failure(old);
return old;
}
} else {
//to區中申請內存成功
const intx interval = PrefetchCopyIntervalInBytes;
Prefetch::write(obj, interval);
//對象複製
Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)obj, s);
//增加年齡,並修改age_table,增加對應年齡的總對象大小
//注意此處是增加複製對象而非原來對象的分代年齡
obj->incr_age();
age_table()->add(obj, s);
}
//將對象頭指針指向新地址
old->forward_to(obj);
return obj;
}
}
//定義垃圾回收器使用的全局屬性,並初始化分代內存及其他共享資源
// CollectorPolicy
// G1CollectorPolicy
// G1CollectorPolicyExt
// GenCollectorPolicy
// TwoGenerationCollectorPolicy
// ConcurrentMarkSweepPolicy
// ASConcurrentMarkSweepPolicy
// GenerationSizer
// MarkSweepPolicy
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class CollectorPolicy : public CHeapObj<mtGC> {
//跟蹤分代內存的性能的計數器
GCPolicyCounters* _gc_policy_counters;
//初始堆內存
size_t _initial_heap_byte_size;
//最大堆內存
size_t _max_heap_byte_size;
//最小堆內存
size_t _min_heap_byte_size;
//space分配粒度
size_t _space_alignment;
//heap分配粒度,_heap_alignment必須大於_space_alignment,且是_space_alignment的整數倍
size_t _heap_alignment;
//是否通過命令行參數設置了最大堆內存
bool _max_heap_size_cmdline;
//用來自適應調整堆內存大小的策略實現
AdaptiveSizePolicy* _size_policy;
//是否需要清除所有的軟引用,當軟引用清除結束,垃圾回收器會將其置爲false
bool _should_clear_all_soft_refs;
//當GC剛清除完所有的軟引用時會設置該屬性爲true,當返回mutator時被設置成false
bool _all_soft_refs_clear;
enum Name {
CollectorPolicyKind,
TwoGenerationCollectorPolicyKind,
ConcurrentMarkSweepPolicyKind,
ASConcurrentMarkSweepPolicyKind,
G1CollectorPolicyKind
};
virtual CollectorPolicy::Name kind() {
return CollectorPolicy::CollectorPolicyKind;
}
}
//表示分代內存使用的CollectorPolicy
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class GenCollectorPolicy : public CollectorPolicy {
//gen0的內存最小值
size_t _min_gen0_size;
//gen0的內存初始值
size_t _initial_gen0_size;
//gen0的內存最大值
size_t _max_gen0_size;
//分代內存分配粒度,_gen_alignment必須被_space_alignment整除,_heap_alignment被_gen_alignment整除
size_t _gen_alignment;
//一種特殊的Generation實現
GenerationSpec **_generations;
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
bool is_tlab) {
//獲取Java堆
GenCollectedHeap *gch = GenCollectedHeap::heap();
//初始化GCCause
GCCauseSetter x(gch, GCCause::_allocation_failure);
HeapWord* result = NULL;
assert(size != 0, "Precondition violated");
if (GC_locker::is_active_and_needs_gc()) {
// GC_locker是active說明還有線程處於JNI關鍵區未開始GC
if (!gch->is_maximal_no_gc()) {
result = expand_heap_and_allocate(size, is_tlab);
}
return result; // could be null if we are out of space
} else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) {
//incremental_collection_will_fail表示如果執行增量收集是否會失敗,參考上一次增量收集的結果
//如果可以執行增量收集
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
} else {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" :: Trying full because partial may fail :: ");
}
//執行全量的full GC
gch->do_collection(true /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
//嘗試分配內存
result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
if (result != NULL) {
//分配成功
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
//分配失敗,嘗試擴展Java堆並分配內存
result = expand_heap_and_allocate(size, is_tlab);
if (result != NULL) {
return result;
}
//分配失敗,說明已經內存不足了,這時需要強制清理軟引用,強制壓實Java堆,任何可能的獲取可用內存的方法都會執行,儘管代價昂貴
//如果嘗試失敗,拋出OOM異常
{
UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
gch->do_collection(true /* full */,
true /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
//再次嘗試分配內存
result = gch->attempt_allocation(size, is_tlab, false /* first_only */);
if (result != NULL) {
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
//分配失敗,軟引用已經清理的,標誌位被置爲false
assert(!should_clear_all_soft_refs(),
"Flag should have been handled and cleared prior to this point");
return NULL;
}
}
//表示一個只有兩個Generation的CollectorPolicy,現有的GenCollectedHeap的所有子類都是隻有兩個Generation,第一個Generation相同,對應GenCollectorPolicy中新增的gen0的相關屬性,第二個Generation的實現各不相同。TwoGenerationCollectorPolicy增加了第二個Generation即gen1相關的屬性
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class TwoGenerationCollectorPolicy : public GenCollectorPolicy {
//gen1的內存最小值
size_t _min_gen1_size;
//gen1的內存初始值
size_t _initial_gen1_size;
//gen1的內存最大值
size_t _max_gen1_size;
}
//UseAdaptiveSizePolicy爲false時使用的CollectorPolicy實現.該類沒有添加新的屬性
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp
class ConcurrentMarkSweepPolicy : public TwoGenerationCollectorPolicy {
void ConcurrentMarkSweepPolicy::initialize_alignments() {
//初始化_space_alignment等屬性
_space_alignment = _gen_alignment = (uintx)Generation::GenGrain;
_heap_alignment = compute_heap_alignment();
}
void ConcurrentMarkSweepPolicy::initialize_generations() {
//初始化_generations
_generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC,
CURRENT_PC, AllocFailStrategy::RETURN_NULL);
if (_generations == NULL)
vm_exit_during_initialization("Unable to allocate gen spec");
//UseParNewGC表示在新生代使用併發收集,默認爲false
if (UseParNewGC) {
if (UseAdaptiveSizePolicy) {
_generations[0] = new GenerationSpec(Generation::ASParNew,
_initial_gen0_size, _max_gen0_size);
} else {
_generations[0] = new GenerationSpec(Generation::ParNew,
_initial_gen0_size, _max_gen0_size);
}
} else {
_generations[0] = new GenerationSpec(Generation::DefNew,
_initial_gen0_size, _max_gen0_size);
}
//UseAdaptiveSizePolicy表示使用自適應策略動態調整各代的大小,默認爲true
if (UseAdaptiveSizePolicy) {
_generations[1] = new GenerationSpec(Generation::ASConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
} else {
_generations[1] = new GenerationSpec(Generation::ConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
}
if (_generations[0] == NULL || _generations[1] == NULL) {
//如果初始化失敗,則退出
vm_exit_during_initialization("Unable to allocate gen spec");
}
}
int number_of_generations() { return 2; }
}
//UseAdaptiveSizePolicy爲true時使用的CollectorPolicy實現.該類沒有添加新的屬性
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp
class ASConcurrentMarkSweepPolicy : public ConcurrentMarkSweepPolicy {
}
垃圾收集器的初始化
根據《JVM內存池》一文中,堆內存初始化
jint Universe::initialize_heap() {
if (UseParallelGC) {
Universe::_collectedHeap = new ParallelScavengeHeap();
} else if (UseG1GC) {
G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt();
g1p->initialize_all();
G1CollectedHeap* g1h = new G1CollectedHeap(g1p);
Universe::_collectedHeap = g1h;
} else {
//主要存儲各種不同收集器堆的模型參數
GenCollectorPolicy *gc_policy;
if (UseSerialGC) {
gc_policy = new MarkSweepPolicy();
} else if (UseConcMarkSweepGC) {
if (UseAdaptiveSizePolicy) {
gc_policy = new ASConcurrentMarkSweepPolicy();
} else {
//cms堆的模型參數
gc_policy = new ConcurrentMarkSweepPolicy();
}
} else { // default old generation
gc_policy = new MarkSweepPolicy();
}
//根據JVM參數,對堆模型參數初始化
gc_policy->initialize_all();
Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
}
//eden中tlab表申請
ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size());
//堆申請,及分帶初始化
jint status = Universe::heap()->initialize();
if (status != JNI_OK) {
return status;
}
// .....
}
其中最常用的爲cms垃圾收集器。其觸發參數爲
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
- Policy中根據參數設置分代數據,根據參數並行gc線程
Threads::create_vm()《openJdk的啓動流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
ConcurrentMarkSweepPolicy::initialize_all
ConcurrentMarkSweepPolicy::initialize_generations # 分代數據設置
GenCollectedHeap::GenCollectedHeap
SharedHeap::SharedHeap # GC線程創建
//年輕代參數設置
_generations[0] = new GenerationSpec(Generation::ParNew,
_initial_gen0_size, _max_gen0_size);
//老年代參數設置
_generations[1] = new GenerationSpec(Generation::ConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
//初始化執行並行GC的線程池
_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
- 根據分代參數,具體初始化分代
Threads::create_vm()《openJdk的啓動流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
GenCollectedHeap::initialize()
//根據各GenerationSpec的最大大小計算總的需要保留的內存空間,然後申請指定大小的連續內存空間
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs);
//分帶初始化
_gen_specs[i]->init(this_rs, i, rem_set());
//年輕代
new ParNewGeneration(rs, init_size(), 0);
//老年代
new ConcurrentMarkSweepGeneration(rs,
init_size(), 1, ctrs, UseCMSAdaptiveFreeLists,
(FreeBlockDictionary<FreeChunk>::DictionaryChoice)CMSDictionaryChoice);
- 驗證堆模型的正確性,及進一些初始化參數,具體參考GenCollectedHeap::post_initialize
垃圾收集觸發
- 創建vm_threads,用於處理虛擬機各種延時任務
Threads::create_vm()《openJdk的啓動流程》中的方法
VMThread::create()
- 編寫一觸放eden垃圾回收代碼
/*-verbose:gc
-Xms20M
-Xmx20M
-Xmn10M
-XX:SurvivorRatio=8
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=1*/
byte[] b1, b2, b3, b4;
b1 = new byte[2 * _1MB];
b2 = new byte[2* _1MB];
b3 = new byte[2* _1MB];
b2 = null;
b3 = null;
b4 = new byte[2* _1MB]; //eden用完,必須回收
- 內存申請失敗生成VM_GenCollectForAllocation並向vm_threads提交
創建b4時通過JNI調用
InterpreterRuntime::newarray
TypeArrayKlass::allocate_common
CollectedHeap::common_mem_allocate_init
GenCollectorPolicy::mem_allocate_work
//VM_GenCollectForAllocation是內存分配失敗觸發垃圾回收,然後嘗試分配內存的操作
VM_GenCollectForAllocation op(size, is_tlab, gc_count_before);
VMThread::execute(&op);
- VMThread處理VM_GenCollectForAllocation事件,進行垃圾回收
VMThread::run
VMThread::loop
VM_Operation::evaluate
VM_GenCollectForAllocation::doit
GenCollectorPolicy::satisfy_failed_allocation
//如果執行增量收集是否會失敗,參考上一次增量收集的結果
if(!incremental_collection_will_fail(false)){
//如果可以執行增量收集
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}else{
//執行全量的full GC
gch->do_collection(true /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
- 根據上例子do_collection執行流程爲
int starting_level = 0;
boolean full = false;
int max_level = 1;
//full爲false,空間不充足
ParNewGeneration.should_collect() //返回true
ParNewGeneration.collect(full, do_clear_all_soft_refs, size, is_tlab);
//full爲false,空間充足
ConcurrentMarkSweepGeneration.should_collect() //false
ParNew年輕代
- 年輕代初始化
Threads::create_vm()《openJdk的啓動流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
GenCollectedHeap::initialize
GenerationSpec::init
ParNewGeneration::ParNewGeneration
DefNewGeneration::DefNewGeneration
//總體申請了個_virtual_space空間
//其中又用EdenSpace,ContiguousSpace進行進一步劃分
_eden_space = new EdenSpace(this);
_from_space = new ContiguousSpace();
_to_space = new ContiguousSpace();
//計算survivor區和eden區的最大空間,即年輕代最大內存時survivor區和eden區的內存空間
uintx size = _virtual_space.reserved_size();
_max_survivor_size = compute_survivor_size(size, alignment);
_max_eden_size = size - (2*_max_survivor_size);
//計算三個內存區的大小和邊界,並初始化
compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
- 年輕代對象分配主要在eden區,只有在eden區和老年代都滿了,纔可能在from區中分配內存,正常情況下to區是空的
數組創建時通過JNI調用
InterpreterRuntime::newarray
TypeArrayKlass::allocate_common
CollectedHeap::common_mem_allocate_init
GenCollectorPolicy::mem_allocate_work
GenCollectedHeap::attempt_allocation
DefNewGeneration::allocate
//正常請求分配eden的空間
//word_size爲此次對象所要的空間
HeapWord* result = eden()->par_allocate(word_size);
if (result != NULL) {
return result;
}
//從from申請空間
result = allocate_from_space(word_size);
- 年輕代垃圾收集ParNewGeneration.collect
//FastScanClosure用來遍歷年輕代中的存活對象oop,第二個參數爲true,表示會將oop對應的卡表項置爲youngergen_card
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier,
gch->rem_set()->klass_rem_set());
//CLDToKlassAndOopClosure用來遍歷一個ClassLoader加載的所有類對應的Class實例和依賴等
CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
&fsc_with_no_gc_barrier,
false)
//上面把所有的遍歷器都準備好了,遍歷器的底層原理是space
//gen_process_roots用於遍歷處理ClassLoaderDataGraph,Threads,Universe等組件中包含的oop,將這些oop作爲根節點遍歷其所引用的其他oop,根據參數還能遍歷年輕代和老年代中的所有oop,遍歷髒的卡表項對應的內存區域中包含的oop
gch->gen_process_roots(_level, //level就是0
true, //因爲level是0,所以此參數實際無意義
true, // StrongRootsScope的active入參爲true
GenCollectedHeap::SO_ScavengeCodeCache, //只遍歷nmethod中的oop
GenCollectedHeap::StrongAndWeakRoots,//StrongAndWeakRoots是靜態常量,值爲false,表示會遍歷weak root,如StringTable中的String對象
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier,
&cld_scan_closure);
- promote 操作
DefNewGeneration::collect
GenCollectedHeap::gen_process_roots
ClassLoaderDataGraph::roots_cld_do
FastScanClosure::do_oop
DefNewGeneration::copy_to_survivor_space
if (old->age() < tenuring_threshold()) {
//如果對象的年齡低於tenuring_threshold,則該在to區申請一塊同樣大小的內存
obj = (oop) to()->allocate_aligned(s);
}
if(obj == null){
//如果如果對象的年齡大於tenuring_threshold或者to區申請內存失敗
//則嘗試將該對象複製到老年代
obj = _next_gen->promote(old, s);
if (obj == NULL) {
//複製失敗
handle_promotion_failure(old);
return old;
}
}else{
//to區中申請內存成功
}
//將對象頭指針指向新地址
old->forward_to(obj);
//promote就是指將某個存活對象oop從eden區拷貝到from區或者老年代的過程
//如果對象年齡大於閾值則拷貝到老年代,否則拷貝到to區
//如果to區內存不足則拷貝到老年代
//如果老年代空間不足則會臨時保存該oop,因爲有可能是該對象較大,此時其他較小的對象可以正常promote成功的。
//從to區或者老年代按照對象大小分配好同樣大小的內存後,就會將舊對象的數據複製到新分配的內存上,然後增加複製對象的對象年齡,最後將複製對象的地址寫入原對象的對象頭中並打標,這個動作就是forword。
CMS老年代垃圾收集
待續
主要參數
《hotspot實戰》
《Hotspot 垃圾回收之VM_Operation 源碼解析》
《Hotspot 垃圾回收之CollectedHeap 源碼解析》
《Hotspot 垃圾回收之GenCollectedHeap 源碼解析》
《Hotspot 垃圾回收之CompactibleSpace 源碼解析》
《Hotspot 垃圾回收之EdenSpace 源碼解析》
《Hotspot 垃圾回收之DefNewGeneration(一) 源碼解析》
《Hotspot 垃圾回收之DefNewGeneration(二) 源碼解析》
《Hotspot 垃圾回收之CollectorPolicy (一) 源碼解析》
《Hotspot 垃圾回收之CollectorPolicy (二) 源碼解析》