CMSCollector 之六
本文讲解剩余的两个步骤Resizing和Resetting以及开启压缩时GC的相关实现。
1、Resizing步骤
前台GC下该步骤是直接将状态_collectorState改成Resetting,实际的resize动作即调用compute_new_size方法是在负责垃圾回收的collect方法整体退出后执行的,如下图:
image.png
前台GC由GenCollectedHeap::do_collection方法调用,在执行完Generation的collect方法后,会执行如下逻辑完成实际的resize,如下:
image.png
后台GC下该步骤会直接调用compute_new_size方法,因为后台GC的全部逻辑都封装在collect_in_background中,没有其他的方法帮助执行相关逻辑,其实现如下:
case Resizing: {
{
ReleaseForegroundGC x(this); // unblock FG collection
MutexLockerEx y(Heap_lock, Mutex::_no_safepoint_check_flag);
CMSTokenSync z(true); // not strictly needed.
if (_collectorState == Resizing) {
compute_new_size();
save_heap_summary();
_collectorState = Resetting;
} else {
assert(_collectorState == Idling, "The state should only change"
" because the foreground collector has finished the collection");
}
}
break;
}
void CMSCollector::compute_new_size() {
assert_locked_or_safepoint(Heap_lock);
FreelistLocker z(this);
MetaspaceGC::compute_new_size();
//其实现与compute_new_size方法基本一致
_cmsGen->compute_new_size_free_list();
}
void CMSCollector::save_heap_summary() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
_last_heap_summary = gch->create_heap_summary();
_last_metaspace_summary = gch->create_metaspace_summary();
}
综上Resizing步骤的核心就是调用compute_new_size方法,根据已使用内存调整老年代以及元空间的当前最大容量,并做适当的扩容或者缩容处理。
2、Resetting 步骤
Resetting 步骤的核心就是下面的reset方法了,该方法主要用来清空整个_markBitMap中已打标的位,如果是异步GC则分段清空,处理期间还需要检查是否需要yeild,如果是同步GC则一次性的完整的清空。
void CMSCollector::reset(bool asynch) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
CMSAdaptiveSizePolicy* sp = size_policy();
//打印日志
AdaptiveSizePolicyOutput(sp, gch->total_collections());
if (asynch) {
//如果是异步GC
//获取CMS Token和bitMapLock锁
CMSTokenSyncWithLocks ts(true, bitMapLock());
//校验状态
if (_collectorState != Resetting) {
assert(_collectorState == Idling, "The state should only change"
" because the foreground collector has finished the collection");
return;
}
//打印日志
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting cmspa(this, "reset", _gc_tracer_cm->gc_id(), !PrintGCDetails);
HeapWord* curAddr = _markBitMap.startWord();
//将整个bitMap分段遍历一遍,清除已打标的位
while (curAddr < _markBitMap.endWord()) {
size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr);
//CMSBitMapYieldQuantum的默认值是10M
MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining));
//将这段范围内的打标的位都清除
_markBitMap.clear_large_range(chunk);
if (ConcurrentMarkSweepThread::should_yield() &&
!foregroundGCIsActive() &&
CMSYield) {
//如果需要执行yield则执行yeild动作
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"CMS thread should hold CMS token");
assert_lock_strong(bitMapLock());
bitMapLock()->unlock();
ConcurrentMarkSweepThread::desynchronize(true);
ConcurrentMarkSweepThread::acknowledge_yield_request();
stopTimer();
if (PrintCMSStatistics != 0) {
incrementYields();
}
icms_wait();
// See the comment in coordinator_yield()
for (unsigned i = 0; i < CMSYieldSleepCount &&
ConcurrentMarkSweepThread::should_yield() &&
!CMSCollector::foregroundGCIsActive(); ++i) {
os::sleep(Thread::current(), 1, false);
ConcurrentMarkSweepThread::acknowledge_yield_request();
}
ConcurrentMarkSweepThread::synchronize(true);
bitMapLock()->lock_without_safepoint_check();
startTimer();
}
//重置起始位置
curAddr = chunk.end();
}
//重置gc_overhead_limit_count
sp->reset_gc_overhead_limit_count();
_collectorState = Idling;
} else {
//同步GC
assert(_collectorState == Resetting, "just checking");
assert_lock_strong(bitMapLock());
//清空整个BitMap
_markBitMap.clear_all();
_collectorState = Idling;
}
//停止增量收集
stop_icms();
//通知GC结束
register_gc_end();
}
void CMSCollector::register_gc_end() {
if (_cms_start_registered) {
report_heap_summary(GCWhen::AfterGC);
_gc_timer_cm->register_gc_end();
_gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
_cms_start_registered = false;
}
}
3、GenMarkSweep
GenMarkSweep封装了开启压缩时执行GC的逻辑,其类继承关系如下:
其中PSMarkSweep是ParallelScavengeHeap即PS算法使用的。MarkSweep定义的属性和方法都是静态的,其属性如下:
- static uint _total_invocations; //记录总的调用次数
- static Stack<oop, mtGC> _marking_stack; //临时保存需要打标的oop
- static Stack<ObjArrayTask, mtGC> _objarray_stack; //临时保存需要打标的数组类的oop
- static Stack<markOop, mtGC> _preserved_mark_stack; //用来保存对象头的Stack,与下面的保存oop的_preserved_oop_stack配合使用,两者的元素一一对象
- static Stack<oop, mtGC> _preserved_oop_stack;
- static size_t _preserved_count;//_preserved_marks的元素个数
- static size_t _preserved_count_max;//_preserved_marks的最大容量
- static PreservedMark* _preserved_marks; //保存PreservedMark指针的数组
- static ReferenceProcessor* _ref_processor; //Reference实例处理器
- static STWGCTimer* _gc_timer; //跟踪GC耗时
- static SerialOldTracer* _gc_tracer; //打印日志
- static KeepAliveClosure keep_alive; //用来判断某个对象是否存活
GenMarkSweep没有新增属性,只新增了一些静态static方法,其中对外的只有一个invoke_at_safepoint方法,下面就顺着这个方法的实现来一次了解相关方法的实现细节。
3.1 allocate_stacks / deallocate_stacks
allocate_stacks就是初始化_preserved_marks,deallocate_stacks则是清空_marking_stack,_objarray_stack等Stack,上述Stack在GenMarkSweep类加载的时候会自动初始化。
void GenMarkSweep::allocate_stacks() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
//实际就是将年轻代的to区的剩余空间都分配了
ScratchBlock* scratch = gch->gather_scratch(gch->_gens[gch->_n_gens-1], 0);
//计算允许的PreservedMark的最大个数
if (scratch != NULL) {
_preserved_count_max =
scratch->num_words * HeapWordSize / sizeof(PreservedMark);
} else {
_preserved_count_max = 0;
}
//初始化
_preserved_marks = (PreservedMark*)scratch;
_preserved_count = 0;
}
void GenMarkSweep::deallocate_stacks() {
if (!UseG1GC) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
//老年代下是空实现,年轻代则是重置to区
gch->release_scratch();
}
//清空Stack
_preserved_mark_stack.clear(true);
_preserved_oop_stack.clear(true);
_marking_stack.clear();
_objarray_stack.clear(true);
}
ScratchBlock* GenCollectedHeap::gather_scratch(Generation* requestor,
size_t max_alloc_words) {
ScratchBlock* res = NULL;
//老年代下该方法使用父类实现,是一个空实现
//年轻代下是将整个to区分配给ScratchBlock
for (int i = 0; i < _n_gens; i++) {
_gens[i]->contribute_scratch(res, requestor, max_alloc_words);
}
//排序的,此处实际只有一个元素,所以排序无意义
sort_scratch_list(res);
return res;
}
上述的PreservedMark就是一个简单的数据结构,用来临时保存并恢复某个对象原来的对象头,其实现如下:
class PreservedMark VALUE_OBJ_CLASS_SPEC {
private:
oop _obj;
markOop _mark;
public:
void init(oop obj, markOop mark) {
_obj = obj;
//原来的对象头
_mark = mark;
}
void adjust_pointer() {
//让obj指向对象头指针中包含的新的对象复制地址
MarkSweep::adjust_pointer(&_obj);
}
void restore() {
//恢复原来的对象头
_obj->set_mark(_mark);
}
};
template <class T> inline void MarkSweep::adjust_pointer(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
//获取p指向的oop
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
//从obj的对象头指针获取复制的目标地址
oop new_obj = oop(obj->mark()->decode_pointer());
assert(new_obj != NULL || // is forwarding ptr?
obj->mark() == markOopDesc::prototype() || // not gc marked?
(UseBiasedLocking && obj->mark()->has_bias_pattern()),
// not gc marked?
"should be forwarded");
if (new_obj != NULL) {
assert(Universe::heap()->is_in_reserved(new_obj),
"should be in object space");
//让p指向新的地址
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
}
}
}
3.2、mark_sweep_phase1
是GenMarkSweep的第一阶段的处理逻辑,负责遍历引用找到存活对象,然后清理找到的References实例,执行类卸载相关的清理工作,其中引用遍历的逻辑封装在GenCollectedHeap::gen_process_roots方法中。
void GenMarkSweep::mark_sweep_phase1(int level,
bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id());
trace(" 1");
GenCollectedHeap* gch = GenCollectedHeap::heap();
//设置遍历的generation
follow_root_closure.set_orig_generation(gch->get_gen(level));
//清除所有的claimed标识
ClassLoaderDataGraph::clear_claimed_marks();
//引用遍历找到存活的对象
gch->gen_process_roots(level,
false, // Younger gens are not roots.
true, // activate StrongRootsScope
GenCollectedHeap::SO_None,
ClassUnloading, //该参数默认为true
&follow_root_closure,
&follow_root_closure,
&follow_cld_closure);
{
ref_processor()->setup_policy(clear_all_softrefs);
//处理找到的References实例
const ReferenceProcessorStats& stats =
ref_processor()->process_discovered_references(
&is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer, _gc_tracer->gc_id());
gc_tracer()->report_gc_reference_stats(stats);
}
// This is the point where the entire marking should have completed.
assert(_marking_stack.is_empty(), "Marking should have completed");
//执行类卸载相关的清理逻辑,跟CMSCollector::refProcessingWork方法中should_unload_classes为true时的逻辑一样
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&is_alive);
// Unload nmethods.
CodeCache::do_unloading(&is_alive, purged_class);
// Prune dead klasses from subklass/sibling/implementor lists.
Klass::clean_weak_klass_links(&is_alive);
// Delete entries for dead interned strings.
StringTable::unlink(&is_alive);
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
gc_tracer()->report_object_count_after_gc(&is_alive);
}
3.3、FollowRootClosure
FollowRootClosure用于以遍历的oop为根节点,通过不断循环遍历所有的各级引用oop,其实现如下:
void MarkSweep::FollowRootClosure::do_oop(oop* p) { follow_root(p); }
void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); }
template <class T> inline void MarkSweep::follow_root(T* p) {
assert(!Universe::heap()->is_in_reserved(p),
"roots shouldn't be things within the heap");
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (!obj->mark()->is_marked()) {
mark_object(obj);
//用MarkSweep::mark_and_push方法来处理obj对应的Klass的ClassLoader实例和它引用的其他对象
obj->follow_contents();
}
}
follow_stack();
}
bool is_marked() const {
return (mask_bits(value(), lock_mask_in_place) == marked_value);
}
inline void MarkSweep::mark_object(oop obj) {
#if INCLUDE_ALL_GCS
if (G1StringDedup::is_enabled()) {
//G1算法的处理逻辑
G1StringDedup::enqueue_from_mark(obj);
}
#endif
//获取原来的对象头
markOop mark = obj->mark();
//重置对象头,将其打标
obj->set_mark(markOopDesc::prototype()->set_marked());
if (mark->must_be_preserved(obj)) {
//如果对象头中包含锁,分代年龄等非初始化信息,则将其保存起来
preserve_mark(obj, mark);
}
}
void MarkSweep::preserve_mark(oop obj, markOop mark) {
//优先放到_preserved_marks中,_preserved_marks位于to区,该区域正常是空的
//可以提高内存使用率
if (_preserved_count < _preserved_count_max) {
_preserved_marks[_preserved_count++].init(obj, mark);
} else {
//_preserved_marks满了则放到_preserved_mark_stack中
_preserved_mark_stack.push(mark);
_preserved_oop_stack.push(obj);
}
}
inline void oopDesc::follow_contents(void) {
assert (is_gc_marked(), "should be marked");
klass()->oop_follow_contents(this);
}
inline bool oopDesc::is_gc_marked() const {
return mark()->is_marked();
}
void InstanceKlass::oop_follow_contents(oop obj) {
assert(obj != NULL, "can't follow the content of NULL object");
//遍历Klass对应的ClassLoader实例
MarkSweep::follow_klass(obj->klass());
//遍历obj所引用的其他oop,使用mark_and_push方法处理找到的oop
InstanceKlass_OOP_MAP_ITERATE( \
obj, \
MarkSweep::mark_and_push(p), \
assert_is_in_closed_subset)
}
inline void MarkSweep::follow_klass(Klass* klass) {
//返回该Klass对应的ClassLoader实例
oop op = klass->klass_holder();
MarkSweep::mark_and_push(&op);
}
virtual oop klass_holder() const { return class_loader(); }
template <class T> inline void MarkSweep::mark_and_push(T* p) {
// assert(Universe::heap()->is_in_reserved(p), "should be in object space");
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (!obj->mark()->is_marked()) {
//将该对象打标并放入_marking_stack中
mark_object(obj);
_marking_stack.push(obj);
}
}
}
void MarkSweep::follow_stack() {
do {
while (!_marking_stack.is_empty()) {
oop obj = _marking_stack.pop();
assert (obj->is_gc_marked(), "p must be marked");
//遍历obj所引用的其他其他对象,并通过while循环,实现以obj为根节点不断遍历各级引用的效果
obj->follow_contents();
}
//遍历引用类型属性时如果该类是数组实例,则将其加入到_objarray_stack中
if (!_objarray_stack.is_empty()) {
ObjArrayTask task = _objarray_stack.pop();
ObjArrayKlass* k = (ObjArrayKlass*)task.obj()->klass();
//同上遍历数组所引用的其他oop
k->oop_follow_contents(task.obj(), task.index());
}
} while (!_marking_stack.is_empty() || !_objarray_stack.is_empty()); //不断遍历直到_marking_stack或者_objarray_stack为空
}
3.4、IsAliveClosure / KeepAliveClosure / FollowStackClosure
IsAliveClosure用于判断某个oop是否是存活的,KeepAliveClosure 用于将某个不是存活的oop标记成存活的,FollowStackClosure用于集中处理KeepAliveClosure打标的那些oop,在某一类Reference实例列表遍历完成后调用其do_void方法。
//根据对象头判断是否打标
bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked(); }
void MarkSweep::KeepAliveClosure::do_oop(oop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); }
void MarkSweep::KeepAliveClosure::do_oop(narrowOop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); }
template <class T> inline void MarkSweep::KeepAliveClosure::do_oop_work(T* p) {
//如果p的对象头未打标则打标并将其放到_marking_stack中
mark_and_push(p);
}
//以_marking_stack中的oop为根节点,不断遍历其所引用的其他oop并打标
void MarkSweep::FollowStackClosure::do_void() { follow_stack(); }
3.5 mark_sweep_phase2
mark_sweep_phase2是GenMarkSweep的第二个步骤,会将对象头打标的对象一个一个的紧挨着放在Space中,从而实现空间压缩的效果,并以此来计算对象复制的目标地址,注意是先压缩老年代中的对象,再压缩年轻代,压缩年轻代时优先将对象放到老年代,老年代空间不足了才会放到年轻代。
void GenMarkSweep::mark_sweep_phase2() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id());
trace("2");
gch->prepare_for_compaction();
}
void GenCollectedHeap::prepare_for_compaction() {
guarantee(_n_gens = 2, "Wrong number of generations");
Generation* old_gen = _gens[1];
// Start by compacting into same gen.
CompactPoint cp(old_gen);
//先压缩老年代
old_gen->prepare_for_compaction(&cp);
Generation* young_gen = _gens[0];
//再压缩年轻代,年轻代的对象首先是拷贝到老年代,如果老年代空间不足则
//拷贝到年轻代
young_gen->prepare_for_compaction(&cp);
}
//年轻代和老年代都使用Generation的默认实现
void Generation::prepare_for_compaction(CompactPoint* cp) {
//老年代下first_compaction_space就是cmsSpace,next_compaction_space是null
//年轻代下first_compaction_space就是eden区,eden区的next_compaction_space是from,from的next_compaction_space是NULL,如果出现promote失败则from区的next_compaction_space是to区
CompactibleSpace* space = first_compaction_space();
while (space != NULL) {
space->prepare_for_compaction(cp);
space = space->next_compaction_space();
}
}
与next_compaction_space方法对应的set_next_compaction_space方法的调用链如下:
image.png
即初始化时next_compaction_space都是null,经过一次年轻代GC后eden区的next_compaction_space是from,from的next_compaction_space是NULL,如果出现promote失败则from区的next_compaction_space是to区。
3.6、mark_sweep_phase3
mark_sweep_phase3是GenMarkSweep的第三个步骤,用于遍历年轻代和老年中包含的所有对象,调整每个对象的引用类型属性,让其指向新的复制地址。
void GenMarkSweep::mark_sweep_phase3(int level) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Adjust the pointers to reflect the new locations
GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id());
trace("3");
//清除ClassLoaderData的claimed标识
ClassLoaderDataGraph::clear_claimed_marks();
adjust_pointer_closure.set_orig_generation(gch->get_gen(level));
//遍历根节点oop*,如果其指向的对象包含复制地址,则让其指向新地址
gch->gen_process_roots(level,
false, // Younger gens are not roots.
true, // activate StrongRootsScope
GenCollectedHeap::SO_AllCodeCache,
GenCollectedHeap::StrongAndWeakRoots,
&adjust_pointer_closure,
&adjust_pointer_closure,
&adjust_cld_closure);
gch->gen_process_weak_roots(&adjust_pointer_closure);
//调整_preserved_marks和_preserved_oop_stack保存的oop,让他们指向新的地址
adjust_marks();
GenAdjustPointersClosure blk;
//遍历老年代和年轻代中所有对象,遍历每个对象所引用的其他对象,调整其地址指向新的地址
gch->generation_iterate(&blk, true);
}
//让p指向新的复制地址
void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p); }
void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); }
CLDToOopClosure MarkSweep::adjust_cld_closure(&adjust_pointer_closure);
void CLDToOopClosure::do_cld(ClassLoaderData* cld) {
//_klass_closure就是KlassToOopClosure,将对klass的遍历转换成对对应的类Class实例的遍历
//_must_claim_cld默认为true,遍历ClassLoaderData重复遍历
cld->oops_do(_oop_closure, &_klass_closure, _must_claim_cld);
}
void MarkSweep::adjust_marks() {
assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(),
"inconsistent preserved oop stacks");
//遍历_preserved_marks
for (size_t i = 0; i < _preserved_count; i++) {
//让_preserved_marks中的oop指向对象头中包含的新的地址
_preserved_marks[i].adjust_pointer();
}
//遍历_preserved_oop_stack
StackIterator<oop, mtGC> iter(_preserved_oop_stack);
while (!iter.is_empty()) {
oop* p = iter.next_addr();
//p指向对象头中包含的新地址
adjust_pointer(p);
}
}
void GenCollectedHeap::generation_iterate(GenClosure* cl,
bool old_to_young) {
if (old_to_young) {
for (int i = _n_gens-1; i >= 0; i--) {
cl->do_generation(_gens[i]);
}
} else {
for (int i = 0; i < _n_gens; i++) {
cl->do_generation(_gens[i]);
}
}
}
class GenAdjustPointersClosure: public GenCollectedHeap::GenClosure {
public:
void do_generation(Generation* gen) {
gen->adjust_pointers();
}
};
void Generation::adjust_pointers() {
AdjustPointersClosure blk;
//遍历每个Space
space_iterate(&blk, true);
}
class AdjustPointersClosure: public SpaceClosure {
public:
void do_space(Space* sp) {
//会遍历Space中所有对象
sp->adjust_pointers();
}
};
3.7、mark_sweep_phase4
mark_sweep_phase4是GenMarkSweep的第四个步骤,遍历年轻代和老年代所有的Space,将对象头打标的对象复制到对象头中包含的新地址上,从而实现对象压缩,在复制的过程中,未打标的对象就会被复制对象所覆盖,从而实现垃圾回收的效果。
void GenMarkSweep::mark_sweep_phase4() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id());
trace("4");
GenCompactClosure blk;
//遍历所有的Space,将所有打标的对象复制到对象头中包含的新的地址,从而实现空间压缩
gch->generation_iterate(&blk, true);
}
class GenCompactClosure: public GenCollectedHeap::GenClosure {
public:
void do_generation(Generation* gen) {
gen->compact();
}
};
void Generation::compact() {
CompactibleSpace* sp = first_compaction_space();
while (sp != NULL) {
sp->compact();
sp = sp->next_compaction_space();
}
}
3.8、invoke_at_safepoint
invoke_at_safepoint就是GenMarkSweep对外的负责执行堆内存压缩的GC,其实现如下:
void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp, bool clear_all_softrefs) {
//校验level等于1,1表示老年代,0表示年轻代
guarantee(level == 1, "We always collect both old and young.");
//校验处于安全点上
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
GenCollectedHeap* gch = GenCollectedHeap::heap();
//初始化_ref_processor
assert(ref_processor() == NULL, "no stomping");
assert(rp != NULL, "should be non-NULL");
_ref_processor = rp;
rp->setup_policy(clear_all_softrefs);
GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, _gc_tracer->gc_id());
gch->trace_heap_before_gc(_gc_tracer);
//CodeCache的gc_prologue方法是空实现
CodeCache::gc_prologue();
//Threads::gc_prologue底层是避免每个线程的栈帧frame对象,执行frame::gc_prologue方法,将bci转换成bcx
Threads::gc_prologue();
//增加技术
_total_invocations++;
//获取已使用内存空间
size_t gch_prev_used = gch->used();
//保存当前已使用内存区域到_prev_used_region属性
gch->save_used_regions(level);
//初始化_preserved_marks
allocate_stacks();
//引用遍历,将存活的对象的对象头打标
mark_sweep_phase1(level, clear_all_softrefs);
//遍历堆内存所有对象,计算打标对象的复制地址
mark_sweep_phase2();
// Don't add any more derived pointers during phase3
COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity"));
COMPILER2_PRESENT(DerivedPointerTable::set_active(false));
//遍历堆内存所有对象,调整其所有的引用类型属性,让这些属性指向新的地址
mark_sweep_phase3(level);
//执行对象复制
mark_sweep_phase4();
//恢复_preserved_marks和_preserved_oop_stack中保存的oop的对象头
restore_marks();
//保存save_marks属性
gch->save_marks();
//清空_marking_stack,_objarray_stack等Stack,释放_preserved_marks的内存
deallocate_stacks();
//判断是否都压缩完成,压缩完成后used为0
bool all_empty = true;
for (int i = 0; all_empty && i < level; i++) {
Generation* g = gch->get_gen(i);
all_empty = all_empty && gch->get_gen(i)->used() == 0;
}
GenRemSet* rs = gch->rem_set();
Generation* old_gen = gch->get_gen(level);
if (all_empty) {
//清空老年代的内存区域在卡表中的脏卡表项
rs->clear_into_younger(old_gen);
} else {
//部分清空,部分恢复成脏的
rs->invalidate_or_clear(old_gen);
}
//遍历所有线程的所有frame,执行gc_epilogue方法
Threads::gc_epilogue();
CodeCache::gc_epilogue();
JvmtiExport::gc_epilogue();
if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used);
}
//重置为NULL
_ref_processor = NULL;
//更新当前堆内存的使用情况
Universe::update_heap_info_at_gc();
//更新上一次GC时间
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
gch->update_time_of_last_gc(now);
gch->trace_heap_after_gc(_gc_tracer);
}
void MarkSweep::restore_marks() {
assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(),
"inconsistent preserved oop stacks");
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Restoring %d marks",
_preserved_count + _preserved_oop_stack.size());
}
//恢复_preserved_marks中保存的oop的对象头
for (size_t i = 0; i < _preserved_count; i++) {
_preserved_marks[i].restore();
}
//恢复_preserved_oop_stack中保存的oop的对象头
while (!_preserved_oop_stack.is_empty()) {
oop obj = _preserved_oop_stack.pop();
markOop mark = _preserved_mark_stack.pop();
obj->set_mark(mark);
}
}