美文网首页
DefNewGeneration 之二

DefNewGeneration 之二

作者: 程序员札记 | 来源:发表于2022-11-21 20:53 被阅读0次

    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.png

    3、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.png

    4、 ageTable
    ageTable的定义在hotspot\src\share\vm\gc_implementation\shared\ageTable.hpp中,用来记录不同分代年龄的对象的大小,然后据此动态调整tenuring_threshold,重要属性只有一个,如下:

    image.png

    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.png

    6、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;
      }
    
    

    相关文章

      网友评论

          本文标题:DefNewGeneration 之二

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