CMSCollector 之六

2022-12-09  本文已影响0人  程序员札记

本文讲解剩余的两个步骤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的逻辑,其类继承关系如下:

image.png

其中PSMarkSweep是ParallelScavengeHeap即PS算法使用的。MarkSweep定义的属性和方法都是静态的,其属性如下:

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);
  }
}

上一篇下一篇

猜你喜欢

热点阅读