HotSpot Serial收集器

GC在HotSpot中的地位举足轻重。JDK9为止提供了四种收集器:Serial,CMS,Parallel,G1。按机器规模,分代类型,吞吐量,延时,CPU利用率等,结合不同的算法,每种收集器都有各自适用的使用场景,同时衍生出多种GC组合配置。今天来看Serial收集器。

  1. Serial收集器属于分代GC收集器。
  2. 年轻代主要算法为复制算法,老年代主要算法为标记压缩算法。
  3. Serial和SerialOld都是单线程GC。特点是需要STW。
  4. 适用于响应时间要求不高的桌面应用或开发调试环境。

一. Serial收集器初始化

使用 -XX:+UseSerialGC 切换到串行收集器模式,断点调试

hotspot/src/share/vm/runtime/init.cpp

jint init_globals() { jint status = universe_init();}

hotspot/src/share/vm/memory/universe.cpp

jint universe_init() { jint status = Universe::initialize_heap();}

hotspot/src/share/vm/memory/universe.cpp

jint Universe::initialize_heap() {
  _collectedHeap = create_heap();
  status = _collectedHeap->initialize();
}

hotspot/src/share/vm/memory/universe.cpp
使用UseSerialGC策略创建堆

CollectedHeap* Universe::create_heap() {
 if (UseParallelGC) {
    return Universe::create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
  } else if (UseG1GC) {
    return Universe::create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
  } else if (UseConcMarkSweepGC) {
    return Universe::create_heap_with_policy<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
  } else if (UseSerialGC) {
    return Universe::create_heap_with_policy<GenCollectedHeap, MarkSweepPolicy>();
  }
}

hotspot/src/share/vm/memory/universe.inline.hpp
策略模板函数

template <class Heap, class Policy>
CollectedHeap* Universe::create_heap_with_policy() {
  Policy* policy = new Policy(); //创建收集策略 MarkSweepPolicy是GenCollectorPolicy的一种
  policy->initialize_all();
  return new Heap(policy); //创建分代堆具体来说就是GenCollectedHeap
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
GenCollectedHeap是CollectedHeap的一种,CardTableRS处理老年代对年轻代的跨代引用

jint GenCollectedHeap::initialize() {
  // Allocate space for the heap.
  char* heap_address; //堆空间地址
  ReservedSpace heap_rs; //映射堆空间
  size_t heap_alignment = collector_policy()->heap_alignment(); //堆大小
  heap_address = allocate(heap_alignment, &heap_rs); //分配堆空间
  //MemRegion到ReservedSpace的映射
  initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size()));
  //使用MemRegion为CardTableRS分配一块内存
  _rem_set = collector_policy()->create_rem_set(reserved_region());
  set_barrier_set(rem_set()->bs());
  //年轻代空间
  ReservedSpace young_rs = heap_rs.first_part(gen_policy()->young_gen_spec()->max_size(), false, false);
  //初始化年轻代空间
  _young_gen = gen_policy()->young_gen_spec()->init(young_rs, rem_set());
  //老年代空间
  heap_rs = heap_rs.last_part(gen_policy()->young_gen_spec()->max_size());
  ReservedSpace old_rs = heap_rs.first_part(gen_policy()->old_gen_spec()->max_size(), false, false);
  //初始化老年代空间
  _old_gen = gen_policy()->old_gen_spec()->init(old_rs, rem_set());

  return JNI_OK;
}

hotspot/src/share/vm/gc/shared/generationSpec.cpp
创建对应的收集器分代类型,Serial收集器对应DefNewGeneration和TenuredGeneration分代


#if INCLUDE_ALL_GCS
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/cms/parNewGeneration.hpp"
#endif // INCLUDE_ALL_GCS

Generation* GenerationSpec::init(ReservedSpace rs, CardTableRS* remset) {
  switch (name()) {
    case Generation::DefNew:
      return new DefNewGeneration(rs, init_size());
    case Generation::MarkSweepCompact:
      return new TenuredGeneration(rs, init_size(), remset);
    #if INCLUDE_ALL_GCS
    case Generation::ParNew:
      return new ParNewGeneration(rs, init_size());
    case Generation::ConcurrentMarkSweep: {
      ConcurrentMarkSweepGeneration* g = NULL;
      g = new ConcurrentMarkSweepGeneration(rs, init_size(), remset);
      g->initialize_performance_counters();
      return g;
    }
    #endif // INCLUDE_ALL_GCS
}

hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
创建年轻代,DefNewGeneration是Generation的一种,ContiguousSpace继承CompactibleSpace间接继承自Space

DefNewGeneration::DefNewGeneration(ReservedSpace rs,
                                   size_t initial_size,
                                   const char* policy)
  : Generation(rs, initial_size),
    _preserved_marks_set(false /* in_c_heap */),
    _promo_failure_drain_in_progress(false),
    _should_allocate_from_space(false)
{
 //初始化MemRegion
  MemRegion cmr((HeapWord*)_virtual_space.low(),
                (HeapWord*)_virtual_space.high());
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  //初始化卡表CardTableModRefBS
  gch->barrier_set()->resize_covered_region(cmr);
  //创建eden,from,to三块连续空间
  _eden_space = new ContiguousSpace();
  _from_space = new ContiguousSpace();
  _to_space   = new ContiguousSpace();
  //计算空间尺寸
  uintx alignment = gch->collector_policy()->space_alignment();
  uintx size = _virtual_space.reserved_size();
  _max_survivor_size = compute_survivor_size(size, alignment);
  _max_eden_size = size - (2*_max_survivor_size);
  //计算三块空间的边界
  compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
  _old_gen = NULL;
  //晋升到老年代阈值
  _tenuring_threshold = MaxTenuringThreshold;
  _pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize;
  //计时器
  _gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
}

hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp
创建老年代,tenuredGeneration是CardGeneration的一种

TenuredGeneration::TenuredGeneration(ReservedSpace rs,
                                     size_t initial_byte_size,
                                     CardTableRS* remset) :
  CardGeneration(rs, initial_byte_size, remset)
{
  HeapWord* bottom = (HeapWord*) _virtual_space.low();
  HeapWord* end    = (HeapWord*) _virtual_space.high();
  _the_space  = new TenuredSpace(_bts, MemRegion(bottom, end));
  _the_space->reset_saved_mark();
  _gc_stats = new GCStats();
  const char* gen_name = "old";
  GenCollectorPolicy* gcp = GenCollectedHeap::heap()->gen_policy();
  // Generation Counters -- generation 1, 1 subspace
  _gen_counters = new GenerationCounters(gen_name, 1, 1,gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
  _gc_counters = new CollectorCounters("MSC", 1);
  _space_counters = new CSpaceCounters(gen_name, 0,_virtual_space.reserved_size(),_the_space, _gen_counters);
}

hotspot/src/share/vm/gc/shared/cardGeneration.cpp

CardGeneration::CardGeneration(ReservedSpace rs,
                               size_t initial_byte_size,
                               CardTableRS* remset) :
  Generation(rs, initial_byte_size), _rs(remset),
  _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
  _used_at_prologue()
{
  HeapWord* start = (HeapWord*)rs.base(); //起始
  size_t reserved_byte_size = rs.size(); //空间大小
  MemRegion reserved_mr(start, heap_word_size(reserved_byte_size));
  //BlockOffsetSharedArray辅助提升对象起始地址查找效率
  _bts = new BlockOffsetSharedArray(reserved_mr,heap_word_size(initial_byte_size));
  MemRegion committed_mr(start, heap_word_size(initial_byte_size));
  _rs->resize_covered_region(committed_mr);
  _min_heap_delta_bytes = MinHeapDeltaBytes;
  _capacity_at_prologue = initial_byte_size;
  _used_at_prologue = 0;
}

hotspot/src/share/vm/gc/shared/generation.cpp

Generation::Generation(ReservedSpace rs, size_t initial_size) :
  _ref_processor(NULL) {
  //初始化虚空间,ReservedSpace到VirtualSpace的映射
  _virtual_space.initialize(rs, initial_size)
  //VirtualSpace到MemRegion的映射
  _reserved = MemRegion((HeapWord*)_virtual_space.low_boundary(),
          (HeapWord*)_virtual_space.high_boundary());
}

二.分代

hotspot/src/share/vm/gc/shared/generation.hpp
分代基类提供了一组虚函数,包括对象分配,对象提升,内存回收,压缩,对象遍历等,模板设计模式具体算法由各子类提供

class Generation: public CHeapObj<mtGC> {
  //
  virtual HeapWord* allocate(size_t word_size, bool is_tlab) = 0;
  virtual HeapWord* par_allocate(size_t word_size, bool is_tlab) = 0;
  virtual oop promote(oop obj, size_t obj_size);
  virtual oop par_promote(int thread_num, oop obj, markOop m, size_t word_sz);
  virtual void collect(bool   full,bool   clear_all_soft_refs,size_t word_size,bool   is_tlab) = 0;
  virtual HeapWord* expand_and_allocate(size_t word_size, bool is_tlab, bool parallel = false) = 0;
 // Mark sweep support phase2
  virtual void prepare_for_compaction(CompactPoint* cp);
  // Mark sweep support phase3
  virtual void adjust_pointers();
  // Mark sweep support phase4
  virtual void compact();
  virtual void post_compact() { ShouldNotReachHere(); }
  ReferenceProcessor* const ref_processor() { return _ref_processor; }
  virtual void oop_iterate(ExtendedOopClosure* cl);
  virtual void object_iterate(ObjectClosure* cl);
  virtual void safe_object_iterate(ObjectClosure* cl);
  virtual void younger_refs_iterate(OopsInGenClosure* cl, uint n_threads) = 0;
  virtual void clear_remembered_set() { }
  virtual void invalidate_remembered_set() { }
  virtual HeapWord* block_start(const void* addr) const;
                                       
}

hotspot/src/share/vm/gc/serial/defNewGeneration.hpp
年轻代DefNewGeneration提供了如年龄表,标记栈,对象遍历操作等,并实现了基类的虚函数

class DefNewGeneration: public Generation {
   AgeTable    _age_table;
   Stack<oop, mtGC> _promo_failure_scan_stack;
   oop copy_to_survivor_space(oop old);
   class FastKeepAliveClosure: public KeepAliveClosure {virtual void do_oop(oop* p);}
   void compute_space_boundaries(uintx minimum_eden_size,bool clear_space,bool mangle_space);
   size_t adjust_for_thread_increase(size_t new_size_candidate,size_t new_size_before,size_t alignment) const;
   void swap_spaces(); //from,to空间交换
   //......
}

hotspot/src/share/vm/gc/shared/cardGeneration.hpp
老年代TenuredGeneration继承自CardGeneration,提供了卡表,块偏移集合,并实现了基类的虚函数

class CardGeneration: public Generation {
  // This is shared with other generations.
  CardTableRS* _rs;
  // This is local to this generation.
  BlockOffsetSharedArray* _bts;
  void space_iterate(SpaceClosure* blk, bool usedOnly = false);
  //对年轻代的引用遍历
  void younger_refs_iterate(OopsInGenClosure* blk, uint n_threads);
  //......
}

HotSpot中的分代在每种收集器中都有自己的实现,CMS是Serial的并发版本,因此共享了部分分代逻辑。如CMS的年轻代ParNewGeneration 集成自 DefNewGeneration 。CMS老年代ConcurrentMarkSweepGeneration:继承自CardGeneration。而Parallel的分代则另起炉灶,Parallel的年轻代为PSYoungGen,老年代为PSOldGen,两者皆集成自CHeapObj。而G1更进一步,由于其算法的特殊性,将空间离散化为多个堆区间,并将gen,from,to,old的堆空间映射到这些离散的堆空间上,分代的概念在此被拆散了。

三.堆空间。

Serial收集器初始化时会创建收集堆GenCollectedHeap继承自CollectedHeap,CollectedHeap的子类还有G1CollectedHeap,ParallelScavengeHeap两者分别用于G1和Parallel收集器。
hotspot/src/share/vm/gc/shared/collectedHeap.hpp
CollectedHeap 提供了一组虚函数,由子类实现堆内存的分配,垃圾收集,管理

class CollectedHeap : public CHeapObj<mtInternal> {
   MemRegion _reserved; //对应的内存区
   BarrierSet* _barrier_set; //读写屏障
   virtual HeapWord* allocate_new_tlab(size_t size); //分配TLAB
   inline static HeapWord* allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size);//通用分配
   inline static HeapWord* common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS);
   virtual bool is_in(const void* p) const = 0; //对象存在判断
   inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);//对象分配
   virtual HeapWord* mem_allocate(size_t size,bool* gc_overhead_limit_was_exceeded) = 0;
   virtual void collect(GCCause::Cause cause) = 0; //收集
   virtual void do_full_collection(bool clear_all_soft_refs) = 0;//全量收集
   virtual void object_iterate(ObjectClosure* cl) = 0; //对象遍历
   virtual HeapWord* block_start(const void* addr) const = 0;
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp
GenCollectedHeap代表年轻代,老年代的分代堆。提供了一组算法用于实现对象分配,对象遍历,垃圾收集,其中一些与CMS收集器共享复用。

class GenCollectedHeap : public CollectedHeap {
  Generation* _young_gen;
  Generation* _old_gen;
  CardTableRS* _rem_set;
  SubTasksDone* _process_strong_tasks; //并行收集有关
  void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab,
                          bool run_verification, bool clear_soft_refs,
                          bool restore_marks_for_biased_locking);
 void do_collection(bool           full,
                     bool           clear_all_soft_refs,
                     size_t         size,
                     bool           is_tlab,
                     GenerationType max_generation);
 HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab);
 WorkGang* workers() const { return _workers; } //并行收集有关
 char* allocate(size_t alignment, ReservedSpace* heap_rs);
 HeapWord* mem_allocate(size_t size, bool*  gc_overhead_limit_was_exceeded);
 void collect(GCCause::Cause cause);
 void collect(GCCause::Cause cause, GenerationType max_generation);
 void oop_iterate_no_header(OopClosure* cl);
 void oop_iterate(ExtendedOopClosure* cl);
 void object_iterate(ObjectClosure* cl);
 void safe_object_iterate(ObjectClosure* cl);
 Space* space_containing(const void* addr) const;
 void generation_iterate(GenClosure* cl, bool old_to_young);
 void process_roots(StrongRootsScope* scope,
                     ScanningOption so,
                     OopClosure* strong_roots,
                     OopClosure* weak_roots,
                     CLDClosure* strong_cld_closure,
                     CLDClosure* weak_cld_closure,
                     CodeBlobToOopClosure* code_roots);
void young_process_roots(StrongRootsScope* scope,
                           OopsInGenClosure* root_closure,
                           OopsInGenClosure* old_gen_closure,
                           CLDClosure* cld_closure);
void cms_process_roots(StrongRootsScope* scope,
                         bool young_gen_as_roots,
                         ScanningOption so,
                         bool only_strong_roots,
                         OopsInGenClosure* root_closure,
                         CLDClosure* cld_closure);
void gen_process_weak_roots(OopClosure* root_closure);
void prepare_for_compaction();
bool create_cms_collector();
}

如同上述分代一样,CMS收集器仍然共享了Serial收集器的分代堆GenCollectedHeap 。而Parallel和G1中则另起炉灶。Parallel的分代堆不再是GenCollectedHeap 而是ParallelScavengeHeap。G1则是G1CollectedHeap。

四.垃圾收集

1.触发GC

修改之前的Hello类如下循环创建大对象,触发GC

import java.util.ArrayList;
import java.util.List;

public class Hello{
    public static void main(String[] args){
        for (int i = 0; i < 5; i++) {
            createBigObject(21);
            System.gc()
        }
    }

    private static void createBigObject(int n) {
        List<byte[]> bytesList = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            bytesList.add(new byte[1024 * 1024 * 10]);
        }
        if (bytesList.size() < 20) {
            throw new RuntimeException("this is test");
        }
    }
}

hotspot/src/share/vm/runtime/vmThread.cpp
VMThread线程循环等待VM_Operation操作的到来,如上一篇当对象分配时空间不足时触发VM_GenCollectForAllocation类型的GC

void VMThread::loop() {
  evaluate_operation(_cur_vm_operation);
}

hotspot/src/share/vm/runtime/vmThread.cpp

void VMThread::evaluate_operation(VM_Operation* op) {
 op->evaluate();
}

hotspot/src/share/vm/runtime/vm_operations.cpp

void VM_Operation::evaluate() {
   doit();
}

hotspot/src/share/vm/gc/shared/vmGCOperations.cpp

void VM_GenCollectForAllocation::doit() {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  GCCauseSetter gccs(gch, _gc_cause);
  _result = gch->satisfy_failed_allocation(_word_size, _tlab);
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp

HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
  return gen_policy()->satisfy_failed_allocation(size, is_tlab);
}

2.收集策略

hotspot/src/share/vm/gc/shared/collectorPolicy.cpp
由收集策略决定收集方式,分配流程如下:

  1. 如果存在GC锁,尝试扩展分配
  2. 如果最近一次回收没有失败,进行一次MinorGC
  3. 如果最近一次回收失败了,进行一次fullGC
  4. 2或3步GC后,再尝试分配
  5. 如果分配还是失败了,尝试扩展堆分配
  6. 如果还是没分配到则一定是堆内存溢出了,强制进行一次FullGC
  7. 强制FullGc后,再次试图分配
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, bool   is_tlab) {
  GenCollectedHeap *gch = GenCollectedHeap::heap();
  GCCauseSetter x(gch, GCCause::_allocation_failure);
  HeapWord* result = NULL;
  if (GCLocker::is_active_and_needs_gc()) {
    //尝试分配
    if (!gch->is_maximal_no_gc()) {
      result = expand_heap_and_allocate(size, is_tlab);
    }
    return result;
  } else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) { //最近一次回收没有失败
    //进行一次MinorGc
    gch->do_collection(false,                     // full
                       false,                     // clear_all_soft_refs
                       size,                      // size
                       is_tlab,                   // is_tlab
                       GenCollectedHeap::OldGen); // max_generation
  } else { //最近一次回收失败了
    //进行一次fullGC
    gch->do_collection(true,                      // full
                       false,                     // clear_all_soft_refs
                       size,                      // size
                       is_tlab,                   // is_tlab
                       GenCollectedHeap::OldGen); // max_generation
  }

  //尝试分配
  result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
  if (result != NULL) {
    return result;
  }

  //尝试扩展堆分配
  result = expand_heap_and_allocate(size, is_tlab);
  if (result != NULL) {
    return result;
  }
  //走到这里一定是内存溢出了,进行一次强制回收,软引用被回收
  {
    UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted

    gch->do_collection(true,                      // full
                       true,                      // clear_all_soft_refs
                       size,                      // size
                       is_tlab,                   // is_tlab
                       GenCollectedHeap::OldGen); // max_generation
  }
  //再次试图分配
  result = gch->attempt_allocation(size, is_tlab, false /* first_only */);
  if (result != NULL) {
    return result;
  }
  //始终没分配到
  return NULL;
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
do_collection是分代堆里封装的适用于各代的收集算法,对哪个分代收集取决于入参。主要流程如下:

  1. 如果do_young_collection成立,进行年轻代回收
  2. 如果最大分代为老年代且老年代应该回收(年轻代空间不足),进行一次老年代回收
  3. 重新调整堆大小
void GenCollectedHeap::do_collection(bool full,......) {
  {
    //进行一次年轻代GC
    if (do_young_collection) {
      collect_generation(_young_gen,
                         full,
                         size,
                         is_tlab,
                         run_verification && VerifyGCLevel <= 0,
                         do_clear_all_soft_refs,
                         false);
    }

    bool must_restore_marks_for_biased_locking = false;
     //进行一次老年代收集
    if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) {
      if (!complete) {
        increment_total_full_collections();
      }
      if (do_young_collection) {
        // 已经进行了一次yuongGC
        GCIdMarkAndRestore gc_id_mark;
        collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true);
      } else {
        // No young GC done. Use the same GC id as was set up earlier in this method.
        collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true);
      }
      collected_old = true;
    }
    //重新调整个代堆大小
    if (collected_old) {
      _old_gen->compute_new_size();
    }
    _young_gen->compute_new_size();
    //重新恢复偏向锁标记
    if (must_restore_marks_for_biased_locking) {
      BiasedLocking::restore_marks();
    }
  }
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
调用具体的分代去回收

void GenCollectedHeap::collect_generation(Generation* gen,...) {
    gen->collect(full, clear_soft_refs, size, is_tlab);
   
}

3.年轻代回收

hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
年轻代回收,使用复制算法,将Eden空间的对象拷贝提升到to空间。各Closure分别对应各种对象遍历操作。主要流程:

  1. 遍历堆空间,线程栈等root引用链,将对象提升。
  2. 遍历所有promote到老年代的对象,恢复其对象头。
  3. Survivor的form和to空间交换。
void DefNewGeneration::collect(bool   full,bool   clear_all_soft_refs,size_t size,bool   is_tlab) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  _old_gen = gch->old_gen();
  // These can be shared for all code paths
  IsAliveClosure is_alive(this);
  ScanWeakRefClosure scan_weak_ref(this);
  age_table()->clear();
  to()->clear(SpaceDecorator::Mangle);
  // The preserved marks should be empty at the start of the GC.
  _preserved_marks_set.init(1);
  gch->rem_set()->prepare_for_younger_refs_iterate(false);
  // Not very pretty.
  CollectorPolicy* cp = gch->collector_policy();
  FastScanClosure fsc_with_no_gc_barrier(this, false);
  FastScanClosure fsc_with_gc_barrier(this, true);
  KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier, gch->rem_set()->klass_rem_set());
  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 evacuate_followers(gch,&fsc_with_no_gc_barrier,&fsc_with_gc_barrier);
  {
    gch->young_process_roots(&srs,
                             &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);
  const ReferenceProcessorStats& stats =
  rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
                                    NULL, _gc_timer);

  if (!_promotion_failed) {
    swap_spaces();
    adjust_desired_tenuring_threshold();
  } else {
    swap_spaces();   // For uniformity wrt ParNewGeneration.
    from()->set_next_compaction_space(to());
    gch->set_incremental_collection_failed();
  }

}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
根对象遍历

void GenCollectedHeap::young_process_roots(StrongRootsScope* scope,
                                           OopsInGenClosure* root_closure,
                                           OopsInGenClosure* old_gen_closure,
                                           CLDClosure* cld_closure) {
  MarkingCodeBlobClosure mark_code_closure(root_closure, CodeBlobToOopClosure::FixRelocations);
  process_roots(scope, SO_ScavengeCodeCache, root_closure, root_closure,
                cld_closure, cld_closure, &mark_code_closure);
  process_string_table_roots(scope, root_closure);
  //......
}

hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
根对象遍历,Universe::oops_do是对堆空间的遍历,其他如线程栈上根对象的引用遍历未列出

void GenCollectedHeap::process_roots(StrongRootsScope* scope,
                                     ScanningOption so,
                                     OopClosure* strong_roots,
                                     OopClosure* weak_roots,
                                     CLDClosure* strong_cld_closure,
                                     CLDClosure* weak_cld_closure,
                                     CodeBlobToOopClosure* code_roots) {
  if (!_process_strong_tasks->is_task_claimed(GCH_PS_ClassLoaderDataGraph_oops_do)) {
    ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure);
  }
  // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway
  CodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots;
  bool is_par = scope->n_threads() > 1;
  Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_code_p);
  if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) {
    Universe::oops_do(strong_roots);
  }
  //......
 
}

hotspot/src/share/vm/memory/universe.cpp
OopClosure对应FastScanClosure

void Universe::oops_do(OopClosure* f, bool do_all) {

  f->do_oop((oop*) &_int_mirror);
  //......
}

hotspot/src/share/vm/gc/serial/defNewGeneration.cpp

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

hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp
这里进行对象提升等操作,具体copy_to_survivor_space

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

hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
如果是to空间不足则提升到老年代空间,老年代空间不足时将触发FullGC

oop DefNewGeneration::copy_to_survivor_space(oop old) {
  size_t s = old->size();
  oop obj = NULL;

  // 尝试在to空间分配
  if (old->age() < tenuring_threshold()) {
    obj = (oop) to()->allocate_aligned(s);
  }

  //尝试在老年代分配
  if (obj == NULL) {
    obj = _old_gen->promote(old, s);
    if (obj == NULL) {
      handle_promotion_failure(old);
      return old;
    }
  } else {
    // Copy obj
    Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)obj, s);
    // 递增年龄
    obj->incr_age();
    age_table()->add(obj, s);
  }

  // Done, insert forward pointer to obj in this header
  old->forward_to(obj);

  return obj;
}

4.老年代回收

hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp
老年代收集,使用标记压缩算法,特点是节省空间,防止内存碎片化

void TenuredGeneration::collect(bool   full,
                                bool   clear_all_soft_refs,
                                size_t size,
                                bool   is_tlab) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  //进入收集器
  GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);

}

hotspot/src/share/vm/gc/serial/genMarkSweep.cpp
老年代收集流程如下:

  1. 使用标记栈标记存活对象
  2. 为标记栈中的对象计算一个新地址
  3. 将新地址更新到对象指针
  4. 移动对象到新地址处
void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  set_ref_processor(rp);
  rp->setup_policy(clear_all_softrefs);
  CodeCache::gc_prologue();
  // Increment the invocation count
  _total_invocations++;
  gch->save_used_regions();
  //分配标记栈
  allocate_stacks();
  //标记存活的对象
  mark_sweep_phase1(clear_all_softrefs); 
 //为存活的对象计算一个新的地址
  mark_sweep_phase2();
  //更新存活对象的对象指针
  mark_sweep_phase3();
  //移动存活对象到新的地址处
  mark_sweep_phase4();
  //销毁标记栈
  deallocate_stacks();
  //清除卡表信息
  CardTableRS* rs = gch->rem_set();
  Generation* old_gen = gch->old_gen();
  //不存在引用,则清空。否则刷新
  if (gch->young_gen()->used() == 0) {
    // We've evacuated the young generation.
    rs->clear_into_younger(old_gen);
  } else {
    rs->invalidate_or_clear(old_gen);
  }

}

每一种收集算法都有自己的适用场景。如分代是基于大量对象存活周期较短的原则上产生的。标记压缩是基于空间利用率产生的。复制算法是基于回收效率因素产生的。而收集器是依据问题空间的大小来挑选合适的算法组建的。因此每种收集器都有其适用范围。虚拟机调优便是在问题空间和解空间找到最佳平衡点,这需要对虚拟机的足够了解也需要实践经验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值