1、gc_prologue / gc_epilogue
gc_prologue方法是在GC开始前调用的预处理,gc_epilogue是在GC结束后调用的尾处理,其实现如下:
void DefNewGeneration::gc_prologue(bool full) {
// Ensure that _end and _soft_end are the same in eden space.
eden()->set_soft_end(eden()->end());
}
void DefNewGeneration::gc_epilogue(bool full) {
DEBUG_ONLY(static bool seen_incremental_collection_failed = false;)
assert(!GC_locker::is_active(), "We should not be executing here");
GenCollectedHeap* gch = GenCollectedHeap::heap();
if (full) {
DEBUG_ONLY(seen_incremental_collection_failed = false;)
//正常情况下GC结束后eden区是空的,如果非空说明堆内存满了,eden区中的存活对象未拷贝至老年代中
if (!collection_attempt_is_safe() && !_eden_space->is_empty()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print("DefNewEpilogue: cause(%s), full, not safe, set_failed, set_alloc_from, clear_seen",
GCCause::to_string(gch->gc_cause()));
}
//通知GCH promote事变
gch->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state
//允许使用from区分配对象
set_should_allocate_from_space(); // we seem to be running out of space
} else {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print("DefNewEpilogue: cause(%s), full, safe, clear_failed, clear_alloc_from, clear_seen",
GCCause::to_string(gch->gc_cause()));
}
gch->clear_incremental_collection_failed(); // We just did a full collection
clear_should_allocate_from_space(); // if set
}
} else {
}
if (ZapUnusedHeapArea) {
//mangle三个区
eden()->check_mangled_unused_area_complete();
from()->check_mangled_unused_area_complete();
to()->check_mangled_unused_area_complete();
}
if (!CleanChunkPoolAsync) {
//清空ChunkPool
Chunk::clean_chunk_pool();
}
//更新计数器
update_counters();
gch->collector_policy()->counters()->update_counters();
}
//该方法返回尝试回收垃圾是否是安全的
bool DefNewGeneration::collection_attempt_is_safe() {
if (!to()->is_empty()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" :: to is not empty :: ");
}
//如果to区非空则返回false,正常都是空的
return false;
}
if (_next_gen == NULL) {
//初始化_next_gen,DefNewGeneration第一次准备垃圾回收前_next_gen一直为null
GenCollectedHeap* gch = GenCollectedHeap::heap();
_next_gen = gch->next_gen(this);
}
//判断next_gen是否有充足的空间,允许年轻代的对象复制到老年代中
return _next_gen->promotion_attempt_is_safe(used());
}
两者的调用链如下:
image.png image.png
2、 compute_new_size
compute_new_size用于在GC结束后根据老年代的大小和NewRatio,NewSizeThreadIncrease两个参数重新计算年轻代的大小,并做适当的扩容或者缩容处理。
void DefNewGeneration::compute_new_size() {
//正常from区或者to区在GC结束后都是空的,如果非空则说明堆内存已满
if (!from()->is_empty() || !to()->is_empty()) {
return;
}
int next_level = level() + 1;
GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(next_level < gch->_n_gens,
"DefNewGeneration cannot be an oldest gen");
Generation* next_gen = gch->_gens[next_level];
size_t old_size = next_gen->capacity();
size_t new_size_before = _virtual_space.committed_size();
size_t min_new_size = spec()->init_size();
size_t max_new_size = reserved().byte_size();
assert(min_new_size <= new_size_before &&
new_size_before <= max_new_size,
"just checking");
size_t alignment = Generation::GenGrain;
// 计算年轻代新的大小,基于NewRatio和NewSizeThreadIncrease
size_t desired_new_size = old_size/NewRatio;
//获取非后台线程数
int threads_count = Threads::number_of_non_daemon_threads();
//NewSizeThreadIncrease表示每个非后台线程增加的年轻代的内存大小,默认是4k
size_t thread_increase_size = threads_count * NewSizeThreadIncrease;
desired_new_size = align_size_up(desired_new_size + thread_increase_size, alignment);
// Adjust new generation size
desired_new_size = MAX2(MIN2(desired_new_size, max_new_size), min_new_size);
assert(desired_new_size <= max_new_size, "just checking");
bool changed = false;
if (desired_new_size > new_size_before) {
//如果大于原来的,则需要扩容
size_t change = desired_new_size - new_size_before;
assert(change % alignment == 0, "just checking");
//尝试扩容指定大小的内存
if (expand(change)) {
//扩容成功,置为true
changed = true;
}
}
if (desired_new_size < new_size_before && eden()->is_empty()) {
//则eden区是空的情形下才允许缩容,非空的条件下缩容有可能导致对象丢失
size_t change = new_size_before - desired_new_size;
assert(change % alignment == 0, "just checking");
_virtual_space.shrink_by(change);
changed = true;
}
if (changed) {
//如果改变,则重新计算三个区的内存边界并初始化,compute_space_boundaries方法会保证eden区的内存足够大
compute_space_boundaries(eden()->used(),
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
MemRegion cmr((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
//重置bs对应的覆盖区域
Universe::heap()->barrier_set()->resize_covered_region(cmr);
if (Verbose && PrintGC) {
size_t new_size_after = _virtual_space.committed_size();
size_t eden_size_after = eden()->capacity();
size_t survivor_size_after = from()->capacity();
gclog_or_tty->print("New generation size " SIZE_FORMAT "K->"
SIZE_FORMAT "K [eden="
SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]",
new_size_before/K, new_size_after/K,
eden_size_after/K, survivor_size_after/K);
if (WizardMode) {
gclog_or_tty->print("[allowed " SIZE_FORMAT "K extra for %d threads]",
thread_increase_size/K, threads_count);
}
gclog_or_tty->cr();
}
}
}
GenerationSpec* Generation::spec() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(0 <= level() && level() < gch->_n_gens, "Bad gen level");
return gch->_gen_specs[level()];
}
MemRegion reserved() const { return _reserved; }
bool DefNewGeneration::expand(size_t bytes) {
MutexLocker x(ExpandHeap_lock);
HeapWord* prev_high = (HeapWord*) _virtual_space.high();
//尝试扩容指定大小的内存
bool success = _virtual_space.expand_by(bytes);
if (success && ZapUnusedHeapArea) {
//扩容成功,执行mangle操作
HeapWord* new_high = (HeapWord*) _virtual_space.high();
MemRegion mangle_region(prev_high, new_high);
SpaceMangler::mangle_region(mangle_region);
}
if (GC_locker::is_active()) {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Garbage collection disabled, "
"expanded heap instead");
}
}
return success;
}
其调用链如下:
image.png3、copy_to_survivor_space
copy_to_survivor_space会将对象拷贝到to区或者老年代,如果对象的分代年龄大于tenuring_threshold或者从to区申请内存失败则拷贝到老年代,否则拷贝到to区;如果拷贝到老年代失败,则_promotion_failed置为true,并将该对象保存到_promo_failure_scan_stack栈中。其实现如下:
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;
}
//从请求头中获取对象的年龄
inline uint oopDesc::age() const {
assert(!is_forwarded(), "Attempt to read age from forwarded mark");
if (has_displaced_mark()) {
return displaced_mark()->age();
} else {
return mark()->age();
}
}
uint tenuring_threshold() { return _tenuring_threshold; }
void DefNewGeneration::handle_promotion_failure(oop old) {
if (PrintPromotionFailure && !_promotion_failed) {
gclog_or_tty->print(" (promotion failure size = " SIZE_FORMAT ") ",
old->size());
}
_promotion_failed = true;
_promotion_failed_info.register_copy_failure(old->size());
preserve_mark_if_necessary(old, old->mark());
//将old的对象头指针指向它自己
old->forward_to(old);
//保存promotion失败的对象
_promo_failure_scan_stack.push(old);
//_promo_failure_drain_in_progress初始化为false
if (!_promo_failure_drain_in_progress) {
// prevent recursion in copy_to_survivor_space()
_promo_failure_drain_in_progress = true;
drain_promo_failure_scan_stack();
_promo_failure_drain_in_progress = false;
}
}
void DefNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) {
//是否要保留promotion失败的对象,对象头中包含锁,分代年龄等非初始状态的信息时需要单独保留对象头,否则无法恢复成原来的状态
if (m->must_be_preserved_for_promotion_failure(obj)) {
preserve_mark(obj, m);
}
}
//保留指定的对象和对象头
void DefNewGeneration::preserve_mark(oop obj, markOop m) {
assert(_promotion_failed && m->must_be_preserved_for_promotion_failure(obj),
"Oversaving!");
_objs_with_preserved_marks.push(obj);
_preserved_marks_of_objs.push(m);
}
//用于移除并处理_promo_failure_scan_stack中保存的对象
void DefNewGeneration::drain_promo_failure_scan_stack() {
while (!_promo_failure_scan_stack.is_empty()) {
oop obj = _promo_failure_scan_stack.pop();
//注意promote失败并不会终止根节点遍历,相反还会遍历其引用类型属性
obj->oop_iterate(_promo_failure_scan_stack_closure);
}
}
其调用链如下:
image.png4、 ageTable
ageTable的定义在hotspot\src\share\vm\gc_implementation\shared\ageTable.hpp中,用来记录不同分代年龄的对象的大小,然后据此动态调整tenuring_threshold,重要属性只有一个,如下:
sizes就是保存不同分代年龄的对象的大小的数组。重点关注以下方法的实现,clear方法用于将sizes数组中各元素的值置为0,add方法用于增加某个分代年龄下的对象大小,compute_tenuring_threshold方法用于计算新的tenuring_threshold,保证to区中已使用空间占总空间的比例满足TargetSurvivorRatio的要求,如下:
ageTable::ageTable(bool global) {
clear();
if (UsePerfData && global) {
ResourceMark rm;
EXCEPTION_MARK;
const char* agetable_ns = "generation.0.agetable";
const char* bytes_ns = PerfDataManager::name_space(agetable_ns, "bytes");
//初始化用于收集性能的PerfVariable
for(int age = 0; age < table_size; age ++) {
char age_name[10];
jio_snprintf(age_name, sizeof(age_name), "%2.2d", age);
const char* cname = PerfDataManager::counter_name(bytes_ns, age_name);
_perf_sizes[age] = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes,
CHECK);
}
const char* cname = PerfDataManager::counter_name(agetable_ns, "size");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None,
table_size, CHECK);
}
}
void ageTable::clear() {
//将所有的数组元素的值重置为0
for (size_t* p = sizes; p < sizes + table_size; ++p) {
*p = 0;
}
}
void add(oop p, size_t oop_size) {
add(p->age(), oop_size);
}
void add(uint age, size_t oop_size) {
assert(age > 0 && age < table_size, "invalid age of object");
sizes[age] += oop_size;
}
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
//TargetSurvivorRatio表示GC后Survivor区已使用内存占总内存的比例,默认是50
//计算期望的survivor区的大小
size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
size_t total = 0;
uint age = 1;
assert(sizes[0] == 0, "no objects with age zero should be recorded");
//从低到高依次遍历ageTable,将给分代年龄对应的对象大小加起来,一旦超过desired_survivor_size,则该age就是目标age
//低于该age的对象就会被拷贝到to区,从而保证Survivor区的内存在GC结束后满足TargetSurvivorRatio限制
while (age < table_size) {
total += sizes[age];
// check if including objects of age 'age' made us pass the desired
// size, if so 'age' is the new threshold
if (total > desired_survivor_size) break;
age++;
}
uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;
if (PrintTenuringDistribution || UsePerfData) {
//打印日志,更新PerfData和相关计数器
if (PrintTenuringDistribution) {
gclog_or_tty->cr();
gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)",
desired_survivor_size*oopSize, result, (int) MaxTenuringThreshold);
}
total = 0;
age = 1;
while (age < table_size) {
total += sizes[age];
if (sizes[age] > 0) {
if (PrintTenuringDistribution) {
gclog_or_tty->print_cr("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total",
age, sizes[age]*oopSize, total*oopSize);
}
}
if (UsePerfData) {
_perf_sizes[age]->set_value(sizes[age]*oopSize);
}
age++;
}
if (UsePerfData) {
SharedHeap* sh = SharedHeap::heap();
CollectorPolicy* policy = sh->collector_policy();
GCPolicyCounters* gc_counters = policy->counters();
gc_counters->tenuring_threshold()->set_value(result);
gc_counters->desired_survivor_size()->set_value(
desired_survivor_size*oopSize);
}
}
return result;
}
5、IsAliveClosure / ScanWeakRefClosure / FastKeepAliveClosure
IsAliveClosure用来判断某个oop是否是存活的;ScanWeakRefClosure用于扫描弱引用的;FastKeepAliveClosure继承自KeepAliveClosure,只适用于DefNewGeneration,用于将某个oop标记成存活状态,具体来说就是将该对象拷贝到to区或者老年代,然后更新对象的对象头指针和BS对应的卡表项,从而让is_forwarded方法返回true;上述三个类,除ScanWeakRefClosure定义在hotspot\src\share\vm\memory\genOopClosures.hpp中,另外两个都在同目录的defNewGeneration.hpp中,其实现如下:
//IsAliveClosure只适用于年轻代
DefNewGeneration::IsAliveClosure::IsAliveClosure(Generation* g) : _g(g) {
assert(g->level() == 0, "Optimized for youngest gen.");
}
bool DefNewGeneration::IsAliveClosure::do_object_b(oop p) {
//如果p不在年轻代或者p即将被复制则认为p是存活的
return (HeapWord*)p >= _g->reserved().end() || p->is_forwarded();
}
inline bool oopDesc::is_forwarded() const {
return mark()->is_marked();
}
bool is_marked() const {
return (mask_bits(value(), lock_mask_in_place) == marked_value);
}
ScanWeakRefClosure::ScanWeakRefClosure(DefNewGeneration* g) :
_g(g)
{
assert(_g->level() == 0, "Optimized for youngest generation");
_boundary = _g->reserved().end();
}
template <class T> inline void ScanWeakRefClosure::do_oop_work(T* p) {
//校验oop非空
assert(!oopDesc::is_null(*p), "null weak reference?");
//获取oop
oop obj = oopDesc::load_decode_heap_oop_not_null(p);
//校验obj在年轻代中且不在to区中
if ((HeapWord*)obj < _boundary && !_g->to()->is_in_reserved(obj)) {
//获取obj的拷贝地址,如果该对象因为Space压缩已经有拷贝地址则使用该地址,否则将该对象拷贝到to区或者老年代
//copy_to_survivor_space方法会完成拷贝并返回拷贝到to区或者老年代的新地址,如果拷贝失败返回NULL
oop new_obj = obj->is_forwarded() ? obj->forwardee()
: _g->copy_to_survivor_space(obj);
//将p指向新地址
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
}
}
DefNewGeneration::KeepAliveClosure::
KeepAliveClosure(ScanWeakRefClosure* cl) : _cl(cl) {
GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind.");
_rs = (CardTableRS*)rs;
}
template <class T>
inline void DefNewGeneration::KeepAliveClosure::do_oop_work(T* p) {
_cl->do_oop_nv(p);
if (Universe::heap()->is_in_reserved(p)) {
oop obj = oopDesc::load_decode_heap_oop_not_null(p);
//将对应的卡表项设置为youngergen_card,而非脏的
_rs->inline_write_ref_field_gc(p, obj);
}
//FastKeepAliveClosure只适用于DefNewGeneration
DefNewGeneration::FastKeepAliveClosure::
FastKeepAliveClosure(DefNewGeneration* g, ScanWeakRefClosure* cl) :
DefNewGeneration::KeepAliveClosure(cl) {
_boundary = g->reserved().end();
}
template <class T>
inline void DefNewGeneration::FastKeepAliveClosure::do_oop_work(T* p) {
_cl->do_oop_nv(p);
oop obj = oopDesc::load_decode_heap_oop_not_null(p);
//同KeepAliveClosure的实现,多了一个地址范围的判断
if (((HeapWord*)obj < _boundary) && Universe::heap()->is_in_reserved(p)) {
_rs->inline_write_ref_field_gc(p, obj);
}
}
与is_marked对应的set_marked方法的调用链如下:
image.png6、FastScanClosure / KlassScanClosure / CLDToKlassAndOopClosure / FastEvacuateFollowersClosure
FastScanClosure用于遍历年轻代中的存活对象oop,如果该对象没有promote,则执行promote,根据对象的分代年龄将对象拷贝到to区或者老年代,并将拷贝的目标地址写入对象头中;然后修改oop使其指向对象的新地址,即对象头中的forward指针;最后如果_scanned_klass不为空则标记该klass的oop发生了修改,如果_gc_barrier为true,则会将对象地址对应的卡表项置为youngergen_card。其实现如下:
FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) :
OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
assert(_g->level() == 0, "Optimized for youngest generation");
//初始化成年轻代的终止地址
_boundary = _g->reserved().end();
}
OopsInKlassOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_klass(NULL) {}
inline OopsInGenClosure::OopsInGenClosure(Generation* gen) :
ExtendedOopClosure(gen->ref_processor()), _orig_gen(gen), _rs(NULL) {
set_generation(gen);
}
inline void OopsInGenClosure::set_generation(Generation* gen) {
_gen = gen;
_gen_boundary = _gen->reserved().start();
if (_rs == NULL) {
GenRemSet* rs = SharedHeap::heap()->rem_set();
assert(rs->rs_kind() == GenRemSet::CardTable, "Wrong rem set kind");
_rs = (CardTableRS*)rs;
}
}
template <class T> inline void FastScanClosure::do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
//加载目标oop
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if ((HeapWord*)obj < _boundary) {
//如果obj是年轻代的对象
assert(!_g->to()->is_in_reserved(obj), "Scanning field twice?");
//is_forwarded为true说明该对象已经执行被promote了
//如果为false,则执行promote,即拷贝到to区或者老年代
//new_obj就是执行promote的对象新地址
oop new_obj = obj->is_forwarded() ? obj->forwardee()
: _g->copy_to_survivor_space(obj);
//让p指向对象的新地址
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
if (is_scanning_a_klass()) {
do_klass_barrier();
} else if (_gc_barrier) {
//初始化时_gen_boundary指向年轻代的起始地址,执行GenCollectedHeap::gen_process_roots时会将其置为老年代的起始地址,此时do_barrier会将p对应的卡表项置为youngergen_card
do_barrier(p);
}
}
}
}
//KlassScanClosure会调用set_scanned_klass来设置
bool is_scanning_a_klass() { return _scanned_klass != NULL; }
inline void OopsInKlassOrGenClosure::do_klass_barrier() {
assert(_scanned_klass != NULL, "Must be");
_scanned_klass->record_modified_oops();
}
//因为Klass在元空间中不能使用卡表或者BitMap来记录其引用的oop发生修改的情形,所以借助此字段记录
void record_modified_oops() { _modified_oops = 1; }
template <class T> inline void OopsInGenClosure::do_barrier(T* p) {
assert(generation()->is_in_reserved(p), "expected ref in generation");
//获取p指向的对象地址
T heap_oop = oopDesc::load_heap_oop(p);
assert(!oopDesc::is_null(heap_oop), "expected non-null oop");
//获取heap_oop的完整地址
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
//_gen_boundary是当前generation的起始地址,如果obj小于gen_boundary,说明obj是更年轻的分代中的
//如果generation本身就是年轻代,则if不成立,如果是老年代,则要求obj是年轻代的
if ((HeapWord*)obj < _gen_boundary) {
//将对应的卡表项标记为youngergen_card
_rs->inline_write_ref_field_gc(p, obj);
}
}
KlassScanClosure与FastScanClosure配合使用,用来遍历所引用的oop发生修改的Klass对应的类Class实例,遍历逻辑就是FastScanClosure。其实现如下:
KlassScanClosure::KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
KlassRemSet* klass_rem_set)
: _scavenge_closure(scavenge_closure),
//accumulate_modified_oops属性默认为false,老年代GC时会设置该属性
_accumulate_modified_oops(klass_rem_set->accumulate_modified_oops()) {}
void KlassScanClosure::do_klass(Klass* klass) {
// If the klass has not been dirtied we know that there's
// no references into the young gen and we can skip it.
if (klass->has_modified_oops()) {
if (_accumulate_modified_oops) {
//将_accumulated_modified_oops置为1
klass->accumulate_modified_oops();
}
//将_modified_oops恢复成0
klass->clear_modified_oops();
//通知_scavenge_closure准备扫描klass
_scavenge_closure->set_scanned_klass(klass);
//执行的过程中如果该Klass对应的java_mirror还在年轻代则将该klass的_modified_oops再次置为1
//这样做的目的是确保下一次年轻代GC时还会将该对象作为存活对象处理,直到将其promote到老年代为止
klass->oops_do(_scavenge_closure);
_scavenge_closure->set_scanned_klass(NULL);
}
}
bool has_modified_oops() { return _modified_oops == 1; }
void accumulate_modified_oops() {
if (has_modified_oops()) _accumulated_modified_oops = 1;
}
void clear_modified_oops() { _modified_oops = 0; }
void Klass::oops_do(OopClosure* cl) {
cl->do_oop(&_java_mirror);
}
与has_modified_oops方法对应的record_modified_oops方法的调用链如下:
image.png即主要是在创建Klass的过程中设置java_mirror属性时调用的,该属性也是klass中的唯一一个oop, 即FastScanClosure主要遍历在上一次GC与本次GC之间新加载或者创建的Klass对应的java_mirror。
CLDToKlassAndOopClosure与FastScanClosure,KlassScanClosure配合使用,用来遍历一个ClassLoader实例加载的所有类的Class实例及其关联的依赖,常量池引用等。
CLDToKlassAndOopClosure(KlassClosure* klass_closure,
OopClosure* oop_closure,
bool must_claim_cld) : //DefNewGeneration调用时传入false,因为是单线程GC的,多线程GC时通常传入true
_oop_closure(oop_closure),
_klass_closure(klass_closure),
_must_claim_cld(must_claim_cld) {}
void CLDToKlassAndOopClosure::do_cld(ClassLoaderData* cld) {
cld->oops_do(_oop_closure, _klass_closure, _must_claim_cld);
}
void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
//claim方法用于判断当前ClassLoaderData是否遍历过
if (must_claim && !claim()) {
return;
}
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
_handles.oops_do(f);
if (klass_closure != NULL) {
//遍历该ClassLoaderData加载的所有Klass
classes_do(klass_closure);
}
}
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
klass_closure->do_klass(k);
assert(k != k->next_link(), "no loops!");
}
}
FastEvacuateFollowersClosure比较特殊,主要用来遍历所有被promote到老年代的对象,恢复他们的对象头,并且遍历其包含的所有引用类型属性,其实现如下:
DefNewGeneration::FastEvacuateFollowersClosure::
FastEvacuateFollowersClosure(GenCollectedHeap* gch, int level,
DefNewGeneration* gen,
FastScanClosure* cur, FastScanClosure* older) :
_gch(gch), _level(level), _gen(gen),
_scan_cur_or_nonheap(cur), _scan_older(older)
{}
void DefNewGeneration::FastEvacuateFollowersClosure::do_void() {
do {
//_level是年轻代的level
//单线程GC时,年轻代的saved_mark_word就是top,所以oop_since_save_marks_iterate不做任何护理
//此方法主要是遍历被promote到老年代的对象,因为是单线程执行,所以执行一遍后老年代的no_allocs_since_save_marks方法就会返回true,从而终止遍历
_gch->oop_since_save_marks_iterate(_level, _scan_cur_or_nonheap,
_scan_older);
} while (!_gch->no_allocs_since_save_marks(_level));
guarantee(_gen->promo_failure_scan_is_complete(), "Failed to finish scan");
}
bool GenCollectedHeap::no_allocs_since_save_marks(int level) {
//如果level为0,则处理年轻代和老年代,如果level为1则只处理老年代
for (int i = level; i < _n_gens; i++) {
if (!_gens[i]->no_allocs_since_save_marks()) return false;
}
return true;
}
//执行do_collect方法前,会先执行GenCollectedHeap::save_marks方法,因此年轻代的此方法返回true
bool DefNewGeneration::no_allocs_since_save_marks() {
assert(eden()->saved_mark_at_top(), "Violated spec - alloc in eden");
assert(from()->saved_mark_at_top(), "Violated spec - alloc in from");
return to()->saved_mark_at_top();
}
//DefNewGeneration::save_marks会将该属性置为top
bool saved_mark_at_top() const { return saved_mark_word() == top(); }
7、collect
collect就是DefNewGeneration执行GC的核心方法了,其中根节点遍历由GenCollectedHeap::gen_process_roots实现,找到的根节点oop由FastScanClosure处理,如果该oop是年轻代的则执行promote,拷贝到to区或者老年代,然后让该oop指向新的对象地址。除根节点oop之外,还需要遍历新创建的klass,由FastScanClosure以同样的方式处理器java_mirror属性,即对应类的Class实例。遍历根节点完成后gen_process_roots还需要遍历老年代对应的脏的卡表项对应的内存区域中的对象,需要遍历这些对象的同样在脏的内存区域中的引用类型属性,即老年代对象所引用新的年轻代的oop,同样将这些oop拷贝到to区或者老年代,然后让该oop指向新的对象地址;注意遍历脏的卡表项对应内存区域中的对象时使用的FastScanClosure的第二个参数为true,执行完上述操作后需要将这些oop对应的卡表项置为youngergen_card。
本方法主要完成引用遍历前后的处理逻辑,这里重点关注年轻代三个区的使用。参考上一篇DefNewGeneration
中分析的allocate方法及其相关方法的实现可知,年轻代对象分配主要在eden区,只有在eden区和老年代都满了导致promote失败才可能在from区中分配内存,正常情况下to区是空的,GC引用遍历时会遍历eden区和from区的对象,这个过程中如果存活对象的分代年龄小于tenuring_threshold则会拷贝到to区中并增加分代年龄,大于该阈值的就拷贝到老年代中,遍历结束后如果没有promote失败则认为所有存活对象都已成功复制,会清空eden区和from区,然后交换from区和to区,即空的from区变成to区,包含有存活对象的to区变成from区,如此循环往复,to区会一直是空的;如果老年代空间不足,出现promote失败的情形,则eden区和from区存在尚未复制的存活对象,则不能清空此时的eden区和from区,这时需要将eden区和from区中对象的对象头恢复成初始状态,即去掉forward指针,然后交换from区和to区,并且将交换后的to区作为from区的next_compaction_space(正常是null),从而尽可能的利用剩余的年轻代内存空间,此时的to区因为是原来的包含存活对象的from区,所以不是空的。
//此方法的四个参数只有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的开始时间和原因
_gc_timer->register_gc_start();
DefNewTracer gc_tracer;
gc_tracer.report_gc_start(gch->gc_cause(), _gc_timer->gc_start());
_next_gen = gch->next_gen(this);
//判断老年代是否有足够的空间保存年轻代复制过去的对象
if (!collection_attempt_is_safe()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" :: Collection attempt not 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());
}
size_t DefNewGeneration::used() const {
//to区通常是空的,不计入此处
return eden()->used()
+ from()->used(); // to() is only used during scavenge
}
void DefNewGeneration::init_assuming_no_promotion_failure() {
_promotion_failed = false;
_promotion_failed_info.reset();
from()->set_next_compaction_space(NULL);
}
void set_promo_failure_scan_stack_closure(ExtendedOopClosure *scan_stack_closure) {
_promo_failure_scan_stack_closure = scan_stack_closure;
}
void DefNewGeneration::swap_spaces() {
//交换from区和to区对应的内存区域
ContiguousSpace* s = from();
_from_space = to();
_to_space = s;
//重置eden区的next_compaction_space
eden()->set_next_compaction_space(from());
//将原来的to区的next_compaction_space置为null
from()->set_next_compaction_space(NULL);
if (UsePerfData) {
CSpaceCounters* c = _from_counters;
_from_counters = _to_counters;
_to_counters = c;
}
}
void DefNewGeneration::adjust_desired_tenuring_threshold() {
//重置tenuring_threshold,注意此处传入的是to区的容量,因为对象是往to区拷贝的
_tenuring_threshold =
age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize);
}
void DefNewGeneration::remove_forwarding_pointers() {
RemoveForwardPointerClosure rspc;
//遍历eden区和from区中的对象,将对象头恢复成初始状态,即去掉原来对象头中包含的forward指针,即该对象拷贝的目标地址
eden()->object_iterate(&rspc);
from()->object_iterate(&rspc);
// Now restore saved marks, if any.
assert(_objs_with_preserved_marks.size() == _preserved_marks_of_objs.size(),
"should be the same");
//遍历_objs_with_preserved_marks,恢复其中保存的oop的对象头,里面的对象都是promote失败的对象
while (!_objs_with_preserved_marks.is_empty()) {
oop obj = _objs_with_preserved_marks.pop();
markOop m = _preserved_marks_of_objs.pop();
obj->set_mark(m);
}
//清空两个栈
_objs_with_preserved_marks.clear(true);
_preserved_marks_of_objs.clear(true);
}
class RemoveForwardPointerClosure: public ObjectClosure {
public:
void do_object(oop obj) {
obj->init_mark();
}
};
virtual void update_time_of_last_gc(jlong now) {
_time_of_last_gc = now;
}
网友评论