Hotspot 垃圾回收之DefNewGeneration(二) 源码解析

    目录

1、gc_prologue / gc_epilogue

2、 compute_new_size

3、copy_to_survivor_space

4、 ageTable

5、IsAliveClosure / ScanWeakRefClosure / FastKeepAliveClosure 

6、FastScanClosure / KlassScanClosure / CLDToKlassAndOopClosure / FastEvacuateFollowersClosure

7、collect


本篇博客继续上一篇《Hotspot 垃圾回收之DefNewGeneration(一) 源码解析》讲解DefNewGeneration的GC相关方法的实现。

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->set_incremental_collection_failed(); // Slight lie: a full gc left us in that state
      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,to区只有通过allocate_from_space方法分配对象才会非空,正常都是空的
    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());
}

两者的调用链如下:

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

其调用链如下:

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();
     obj->oop_iterate(_promo_failure_scan_stack_closure);
  }
}

其调用链如下:

4、 ageTable

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

sizes就是保存不同分代年龄的对象的大小的数组。重点关注以下方法的实现,clear方法用于将sizes数组中各元素的值置为0,add方法用于增加某个分代年龄下的对象大小,compute_tenuring_threshold方法用于计算新的tenuring_threshold,保证to区中已使用空间占总空间的比例满足TargetSurvivorRatio的要求,如下:

ageTable::ageTable(bool global) {

  clear();

  if (UsePerfData && global) {

    ResourceMark rm;
    EXCEPTION_MARK;

    const char* agetable_ns = "generation.0.agetable";
    const char* bytes_ns = PerfDataManager::name_space(agetable_ns, "bytes");
    
    //初始化用于收集性能的PerfVariable
    for(int age = 0; age < table_size; age ++) {
      char age_name[10];
      jio_snprintf(age_name, sizeof(age_name), "%2.2d", age);
      const char* cname = PerfDataManager::counter_name(bytes_ns, age_name);
      _perf_sizes[age] = PerfDataManager::create_variable(SUN_GC, cname,
                                                          PerfData::U_Bytes,
                                                          CHECK);
    }

    const char* cname = PerfDataManager::counter_name(agetable_ns, "size");
    PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None,
                                     table_size, CHECK);
  }
}

void ageTable::clear() {
  //将所有的数组元素的值重置为0
  for (size_t* p = sizes; p < sizes + table_size; ++p) {
    *p = 0;
  }
}

void add(oop p, size_t oop_size) {
    add(p->age(), oop_size);
  }

void add(uint age, size_t oop_size) {
    assert(age > 0 && age < table_size, "invalid age of object");
    sizes[age] += oop_size;
  }

uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
  //TargetSurvivorRatio表示GC后Survivor区已使用内存占总内存的比例,默认是50
  //计算期望的survivor区的大小
  size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
  size_t total = 0;
  uint age = 1;
  assert(sizes[0] == 0, "no objects with age zero should be recorded");
  //从低到高依次遍历ageTable,将给分代年龄对应的对象大小加起来,一旦超过desired_survivor_size,则该age就是目标age
  //低于该age的对象就会被拷贝到to区,从而保证Survivor区的内存在GC结束后满足TargetSurvivorRatio限制
  while (age < table_size) {
    total += sizes[age];
    // check if including objects of age 'age' made us pass the desired
    // size, if so 'age' is the new threshold
    if (total > desired_survivor_size) break;
    age++;
  }
  uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;

  if (PrintTenuringDistribution || UsePerfData) {
    //打印日志,更新PerfData和相关计数器
    if (PrintTenuringDistribution) {
      gclog_or_tty->cr();
      gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)",
        desired_survivor_size*oopSize, result, (int) MaxTenuringThreshold);
    }

    total = 0;
    age = 1;
    while (age < table_size) {
      total += sizes[age];
      if (sizes[age] > 0) {
        if (PrintTenuringDistribution) {
          gclog_or_tty->print_cr("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total",
                                        age,    sizes[age]*oopSize,          total*oopSize);
        }
      }
      if (UsePerfData) {
        _perf_sizes[age]->set_value(sizes[age]*oopSize);
      }
      age++;
    }
    if (UsePerfData) {
      SharedHeap* sh = SharedHeap::heap();
      CollectorPolicy* policy = sh->collector_policy();
      GCPolicyCounters* gc_counters = policy->counters();
      gc_counters->tenuring_threshold()->set_value(result);
      gc_counters->desired_survivor_size()->set_value(
        desired_survivor_size*oopSize);
    }
  }

  return result;
}

5、IsAliveClosure / ScanWeakRefClosure / FastKeepAliveClosure 

     IsAliveClosure用来判断某个oop是否是存活的;ScanWeakRefClosure用于扫描弱引用的;FastKeepAliveClosure继承自KeepAliveClosure,只适用于DefNewGeneration,用于将某个oop标记成存活状态,具体来说就是将该对象拷贝到to区或者老年代,然后更新对象的对象头指针和BS对应的卡表项,从而让is_forwarded方法返回true;上述三个类,除ScanWeakRefClosure定义在hotspot\src\share\vm\memory\genOopClosures.hpp中,另外两个都在同目录的defNewGeneration.hpp中,其实现如下:

//IsAliveClosure只适用于年轻代
DefNewGeneration::IsAliveClosure::IsAliveClosure(Generation* g) : _g(g) {
  assert(g->level() == 0, "Optimized for youngest gen.");
}
bool DefNewGeneration::IsAliveClosure::do_object_b(oop p) {
  //如果p不在年轻代或者p即将被复制则认为p是存活的
  return (HeapWord*)p >= _g->reserved().end() || p->is_forwarded();
}

ScanWeakRefClosure::ScanWeakRefClosure(DefNewGeneration* g) :
  _g(g)
{
  assert(_g->level() == 0, "Optimized for youngest generation");
  _boundary = _g->reserved().end();
}

void ScanWeakRefClosure::do_oop(oop* p)       { ScanWeakRefClosure::do_oop_work(p); }
void ScanWeakRefClosure::do_oop(narrowOop* p) { ScanWeakRefClosure::do_oop_work(p); }

inline void ScanWeakRefClosure::do_oop_nv(oop* p)       { ScanWeakRefClosure::do_oop_work(p); }
inline void ScanWeakRefClosure::do_oop_nv(narrowOop* p) { ScanWeakRefClosure::do_oop_work(p); }

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

void DefNewGeneration::KeepAliveClosure::do_oop(oop* p)       { DefNewGeneration::KeepAliveClosure::do_oop_work(p); }
void DefNewGeneration::KeepAliveClosure::do_oop(narrowOop* p) { DefNewGeneration::KeepAliveClosure::do_oop_work(p); }

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

void DefNewGeneration::FastKeepAliveClosure::do_oop(oop* p)       { DefNewGeneration::FastKeepAliveClosure::do_oop_work(p); }
void DefNewGeneration::FastKeepAliveClosure::do_oop(narrowOop* p) { DefNewGeneration::FastKeepAliveClosure::do_oop_work(p); }


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

6、FastScanClosure / KlassScanClosure / CLDToKlassAndOopClosure / FastEvacuateFollowersClosure

      FastScanClosure用于遍历存活对象的引用类型属性,修改该属性的值使其指向对象的新地址,即对象头中的forward指针,最后根据参数修改bs;如果已经有Space压缩生成的forword指针则直接使用,否则根据对象的分代年龄将对象拷贝到to区或者老年代,并将拷贝的目标地址写入对象头中。KlassScanClosure与FastScanClosure配合使用,用来遍历Klass对应的类Class实例,遍历逻辑就是FastScanClosure。CLDToKlassAndOopClosure与FastScanClosure,KlassScanClosure配合使用,用来遍历一个ClassLoader实例加载的所有类的Class实例及其关联的依赖,常量池引用等。FastEvacuateFollowersClosure比较特殊,用来遍历所有Space的_saved_mark_word属性到top属性之间的对象的所有引用类型属性。

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

void FastScanClosure::do_oop(oop* p)       { FastScanClosure::do_oop_work(p); }
void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); }

inline void FastScanClosure::do_oop_nv(oop* p)       { FastScanClosure::do_oop_work(p); }
inline void FastScanClosure::do_oop_nv(narrowOop* p) { FastScanClosure::do_oop_work(p); }

template <class T> inline void FastScanClosure::do_oop_work(T* p) {
  T heap_oop = oopDesc::load_heap_oop(p);
  // Should we copy the obj?
  if (!oopDesc::is_null(heap_oop)) {
    oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
    if ((HeapWord*)obj < _boundary) {
      assert(!_g->to()->is_in_reserved(obj), "Scanning field twice?");
      oop new_obj = obj->is_forwarded() ? obj->forwardee()
                                        : _g->copy_to_survivor_space(obj);
      oopDesc::encode_store_heap_oop_not_null(p, new_obj);
      if (is_scanning_a_klass()) {
        do_klass_barrier();
      } else if (_gc_barrier) {
        // Now call parent closure
        do_barrier(p);
      }
    }
  }
}

OopsInKlassOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_klass(NULL) {}

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

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是更年轻的分代中的
  if ((HeapWord*)obj < _gen_boundary) {
    //将对应的卡表项标记为youngergen_card
    _rs->inline_write_ref_field_gc(p, obj);
  }
}

KlassScanClosure::KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
                                   KlassRemSet* klass_rem_set)
    : _scavenge_closure(scavenge_closure),
      _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) {
      klass->accumulate_modified_oops();
    }

    // Clear this state since we're going to scavenge all the metadata.
    klass->clear_modified_oops();

    //通知_scavenge_closure准备扫描klass
    _scavenge_closure->set_scanned_klass(klass);

    klass->oops_do(_scavenge_closure);

    _scavenge_closure->set_scanned_klass(NULL);
  }
}

void Klass::oops_do(OopClosure* cl) {
  cl->do_oop(&_java_mirror);
}

CLDToKlassAndOopClosure(KlassClosure* klass_closure,
                          OopClosure* oop_closure,
                          bool must_claim_cld) :
                              _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) {
  if (must_claim && !claim()) {
    return;
  }

  f->do_oop(&_class_loader);
  _dependencies.oops_do(f);
  _handles.oops_do(f);
  if (klass_closure != NULL) {
    classes_do(klass_closure);
  }
}

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 {
    _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");
}

7、collect

      collect就是DefNewGeneration执行GC的核心入口方法了,其中引用遍历的逻辑都封装在GenCollectedHeap::gen_process_roots方法中了,本方法主要完成引用遍历前后的处理逻辑,这里重点关注年轻代三个区的使用。参考上一篇《Hotspot 垃圾回收之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区,所以不是空的。

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 :: ");
    }
    //老年代空间不足,终止年轻代的GC
    gch->set_incremental_collection_failed(); // Slight lie: we did not even attempt one
    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*,即Java对象中的引用类型属性
  FastScanClosure fsc_with_no_gc_barrier(this, false);
  FastScanClosure fsc_with_gc_barrier(this, true);
  
  //KlassScanClosure用来遍历某个类对应的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);

  set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
  //FastEvacuateFollowersClosure用来遍历从saved_mark属性到top之间的oop
  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.");
  
  //执行引用遍历
  gch->gen_process_roots(_level,
                         true,  // Process younger gens, if any,
                                // as strong roots.
                         true,  // activate StrongRootsScope
                         GenCollectedHeap::SO_ScavengeCodeCache,
                         GenCollectedHeap::StrongAndWeakRoots,
                         &fsc_with_no_gc_barrier,
                         &fsc_with_gc_barrier,
                         &cld_scan_closure);

  //执行遍历
  evacuate_followers.do_void();

  FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
  ReferenceProcessor* rp = ref_processor();
  rp->setup_policy(clear_all_soft_refs);
  //过滤所有找到的references实例
  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");
    //清空保存promo_failure的oop的栈
    _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());
    gch->set_incremental_collection_failed();

    //通知老年代promote失败.
    _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());
}

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的对象头
  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;
  }
发布了117 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_31865983/article/details/104091873