美文网首页
CMSCollector 之六

CMSCollector 之六

作者: 程序员札记 | 来源:发表于2022-12-09 13:57 被阅读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定义的属性和方法都是静态的,其属性如下:

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

    相关文章

      网友评论

          本文标题:CMSCollector 之六

          本文链接:https://www.haomeiwen.com/subject/rumzfdtx.html