CMSCollector

2022-11-27  本文已影响0人  程序员札记

根据上一篇ConcurrentMarkSweepGeneration 之三 对ConcurrentMarkSweepGeneration主要方法的实现分析可知,老年代的垃圾回收相关细节被完全封装在CMSCollector中,调用入口就是ConcurrentMarkSweepThread调用的CMSCollector::collect_in_background和ConcurrentMarkSweepGeneration调用的CMSCollector::collect方法,从本篇开始就顺着这两个入口的对相关方法的调用顺序,逐步讲解CMSCollector的实现细节,其定义和构造方法已经在ConcurrentMarkSweepGeneration中讲解过了,重点关注相关方法的实现。

1、acquire_control_and_collect
acquire_control_and_collect就是CMSCollector::collect方法的核心实现了,首先会从执行后台GC的CMSThread中获取GC的执行权限,然后判断是否需要压缩老年代,根据是否压缩走不同的标记清理逻辑。其实现如下:

void CMSCollector::acquire_control_and_collect(bool full,
        bool clear_all_soft_refs) {
  //当前线程处于安全点上      
  assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
  //当前线程是VMThread
  assert(!Thread::current()->is_ConcurrentGC_thread(),
         "shouldn't try to acquire control from self!");
 
  //校验VMThread已经获取了CMS Token
  assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
         "VM thread should have CMS token");
  //当前的垃圾回收状态
  CollectorState first_state = _collectorState;
 
  //_foregroundGCIsActive置为true表示前台GC已经激活了
  _foregroundGCIsActive = true;
 
  //临时暂停ICMS模式
  ICMSDisabler icms_disabler;
 
  //校验已经获取了锁
  assert_lock_strong(bitMapLock());
  assert(haveFreelistLocks(), "Must be holding free list locks");
  //释放锁等待后台GC让出GC执行权
  bitMapLock()->unlock();
  releaseFreelistLocks();
  {
    //获取锁CGC_lock
    MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
    if (_foregroundGCShouldWait) {
      //_foregroundGCShouldWait为true,表示后台GC正在进行
      assert(ConcurrentMarkSweepThread::cmst() != NULL,
             "CMS thread must be running");
      //释放VMThread占用的CMS Token
      ConcurrentMarkSweepThread::clear_CMS_flag(
        ConcurrentMarkSweepThread::CMS_vm_has_token);  // release token
      // 唤醒可能等待的CMS Thread继续执行
      CGC_lock->notify();
      assert(!ConcurrentMarkSweepThread::vm_thread_wants_cms_token(),
             "Possible deadlock");       
      while (_foregroundGCShouldWait) {
        //循环等待直到_foregroundGCShouldWait变为false,即后台GC交出了GC执行权
        CGC_lock->wait(Mutex::_no_safepoint_check_flag);
      }
      //重新获取CMS Token
      ConcurrentMarkSweepThread::set_CMS_flag(
        ConcurrentMarkSweepThread::CMS_vm_has_token);
    }
  }
  assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
         "VM thread should have CMS token");
  //重新获取锁       
  getFreelistLocks();
  bitMapLock()->lock_without_safepoint_check();
  if (TraceCMSState) {
    gclog_or_tty->print_cr("CMS foreground collector has asked for control "
      INTPTR_FORMAT " with first state %d", Thread::current(), first_state);
    gclog_or_tty->print_cr("    gets control with state %d", _collectorState);
  }
 
  //判断是否需要进行压缩,如果不需要是否需要标记清理
  bool should_compact    = false;
  bool should_start_over = false;
  decide_foreground_collection_type(clear_all_soft_refs,
    &should_compact, &should_start_over);
 
  
  if (first_state > Idling) {
    //如果当前GC状态不是空闲,则说明后台GC已经完成了部分GC步骤,打印被中断日志
    report_concurrent_mode_interruption();
  }
 
  set_did_compact(should_compact);
  if (should_compact) {
    //清空discovered References链表中的References实例,Mark-Sweep-Compact代码假定他们的referent都不是NULL且
    //References实例都是存活的
    ref_processor()->clean_up_discovered_references();
 
    if (first_state > Idling) {
      //保存当前堆内存和元空间的使用情况
      save_heap_summary();
    }
    //执行压缩并标记清理,底层核心实现是GenMarkSweep
    do_compaction_work(clear_all_soft_refs);
 
    DefNewGeneration* young_gen = _young_gen->as_DefNewGeneration();
    //获取eden区的最大容量
    size_t max_eden_size = young_gen->max_capacity() -
                           young_gen->to()->capacity() -
                           young_gen->from()->capacity();
    GenCollectedHeap* gch = GenCollectedHeap::heap();
    GCCause::Cause gc_cause = gch->gc_cause();
    size_policy()->check_gc_overhead_limit(_young_gen->used(),
                                           young_gen->eden()->used(),
                                           _cmsGen->max_capacity(),
                                           max_eden_size,
                                           full,
                                           gc_cause,
                                           gch->collector_policy());
  } else {
    //执行标记清理
    do_mark_sweep_work(clear_all_soft_refs, first_state,
      should_start_over);
  }
  //清空扩展的原因
  clear_expansion_cause();
  //_foregroundGCIsActive置为false
  _foregroundGCIsActive = false;
  return;
}
 
void CMSCollector::decide_foreground_collection_type(
  bool clear_all_soft_refs, bool* should_compact,
  bool* should_start_over) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  assert(gch->collector_policy()->is_two_generation_policy(),
         "You may want to check the correctness of the following");
 
  if (gch->incremental_collection_will_fail(false /* don't consult_young */)) {
    //如果增量收集会失败
    assert(!_cmsGen->incremental_collection_failed(),
           "Should have been noticed, reacted to and cleared");
    _cmsGen->set_incremental_collection_failed();
  }
  //UseCMSCompactAtFullCollection表示在Full GC时是否执行压缩,默认为true
  //CMSFullGCsBeforeCompaction表示一个阈值,Full GC的次数超过该值才会执行压缩
  *should_compact =
    UseCMSCompactAtFullCollection &&
    ((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||
     GCCause::is_user_requested_gc(gch->gc_cause()) || //用户通过System.gc方法请求GC
     gch->incremental_collection_will_fail(true /* consult_young */)); //增量收集失败
  *should_start_over = false;
  //如果should_compact为false且clear_all_soft_refs为true
  if (clear_all_soft_refs && !*should_compact) {
    //当clear_all_soft_refs为true时是否需要压缩,默认为true
    if (CMSCompactWhenClearAllSoftRefs) {
      *should_compact = true;
    } else {
      //如果当前GC已经过FinalMarking环节了,在该环节才处理所有的Refenrence,则需要重新开始一轮GC,
      //重新查找待处理的Refenrence
      if (_collectorState > FinalMarking) {
        //将GC的状态设置为重置
        _collectorState = Resetting; // skip to reset to start new cycle
        //执行重置
        reset(false /* == !asynch */);
        *should_start_over = true;
      } 
    }
  }
}
 
void CMSCollector::report_concurrent_mode_interruption() {
  if (is_external_interruption()) {
    if (PrintGCDetails) {
      gclog_or_tty->print(" (concurrent mode interrupted)");
    }
  } else {
    if (PrintGCDetails) {
      gclog_or_tty->print(" (concurrent mode failure)");
    }
    _gc_tracer_cm->report_concurrent_mode_failure();
  }
}
 
bool CMSCollector::is_external_interruption() {
  GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause();
  return GCCause::is_user_requested_gc(cause) ||
         GCCause::is_serviceability_requested_gc(cause);
}
 
  inline static bool is_user_requested_gc(GCCause::Cause cause) {
    return (cause == GCCause::_java_lang_system_gc ||
            cause == GCCause::_jvmti_force_gc);
  }
 
  inline static bool is_serviceability_requested_gc(GCCause::Cause
                                                             cause) {
    return (cause == GCCause::_jvmti_force_gc ||
            cause == GCCause::_heap_inspection ||
            cause == GCCause::_heap_dump);
  }
 
void CMSCollector::save_heap_summary() {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  _last_heap_summary = gch->create_heap_summary();
  _last_metaspace_summary = gch->create_metaspace_summary();
}

其调用链如下:

image.png

代码中用到的ICMSDisabler的定义如下:

image.png

2、do_compaction_work
该方法是老年代需要压缩时执行msc_collection即Mark-Sweep-Compact collection的入口方法,核心逻辑都在GenMarkSweep::invoke_at_safepoint方法中,该方法就负责msc_collection开始前的通知和准备,结束后通知和状态重置工作,其实现如下:

void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
 
  //通知计时器和跟踪器 GC开始
  STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
  gc_timer->register_gc_start();
  SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
  gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
 
  GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id());
  if (PrintGC && Verbose && !(GCCause::is_user_requested_gc(gch->gc_cause()))) {
    gclog_or_tty->print_cr("Compact ConcurrentMarkSweepGeneration after %d "
      "collections passed to foreground collector", _full_gcs_since_conc_gc);
  }
 
  if (UseAdaptiveSizePolicy) {
    //msc就是Mark-Sweep-Compact的简写,通知CMSAdaptiveSizePolicy GC开始
    size_policy()->msc_collection_begin();
  }
 
  
  MemRegion new_span(GenCollectedHeap::heap()->reserved_region());
  //暂时修改ref_processor的span属性为new_span
  ReferenceProcessorSpanMutator rp_mut_span(ref_processor(), new_span);
  //暂时修改ref_processor的is_alive_non_header属性为NULL
  ReferenceProcessorIsAliveMutator rp_mut_closure(ref_processor(), NULL);
  //暂时修改 _processing_is_mt属性为false
  ReferenceProcessorMTProcMutator rp_mut_mt_processing(ref_processor(), false);
  //暂时修改discovery_is_atomic属性为true
  ReferenceProcessorAtomicMutator rp_mut_atomic(ref_processor(), true);
  //暂时修改 discovery_is_mt属性为false
  ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false);
 
  ref_processor()->set_enqueuing_is_done(false);
  //允许Reference实例查找
  ref_processor()->enable_discovery(false /*verify_disabled*/, false /*check_no_refs*/);
  //设置清除策略
  ref_processor()->setup_policy(clear_all_soft_refs);
 
  assert(_collectorState != Idling || _modUnionTable.isAllClear(),
    "_modUnionTable should be clear if the baton was not passed");
  //清空_modUnionTable中的标记
  _modUnionTable.clear_all();
  assert(_collectorState != Idling || _ct->klass_rem_set()->mod_union_is_clear(),
    "mod union for klasses should be clear if the baton was passed");
  //遍历Klass清理_accumulated_modified_oops标识  
  _ct->klass_rem_set()->clear_mod_union();
 
  //没开始GC,所以_intra_sweep_timer不是激活的,此时_inter_sweep_timer应该是激活的
  assert(!_intra_sweep_timer.is_active(), "_intra_sweep_timer should be inactive");
  if (_inter_sweep_timer.is_active()) {
    //停止计时
    _inter_sweep_timer.stop();
    //重置cmsSpace内存块合并相关的计数器
    _cmsGen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
                                            _inter_sweep_estimate.padded_average(),
                                            _intra_sweep_estimate.padded_average());
  }
  //执行压缩,标记清理等垃圾回收步骤
  GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
    ref_processor(), clear_all_soft_refs);
  
  //重置_collectorState和CMSCollector
  _collectorState = Resetting;
  assert(_restart_addr == NULL,
         "Should have been NULL'd before baton was passed");
  reset(false /* == !asynch */);
  //老年代压缩后的重置
  _cmsGen->reset_after_compaction();
  _concurrent_cycles_since_last_unload = 0;
 
  //重置PLAB ChunkArray数组
  if (_survivor_plab_array != NULL) {
    reset_survivor_plab_arrays();
  }
 
  //GC结束重置cmsSpace内存块合并相关的计数器
  _cmsGen->cmsSpace()->endSweepFLCensus(sweep_count() /* fake */);
  //_inter_sweep_timer重置
  _inter_sweep_timer.reset();
  _inter_sweep_timer.start();
 
  //通知GC结束
  if (UseAdaptiveSizePolicy) {
    size_policy()->msc_collection_end(gch->gc_cause());
  }
  gc_timer->register_gc_end();
  gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
 
  //注意此情形下compute_new_size由上层的GenCollectHeap的do_collect方法调用
}
 
void CMSCollector::reset_survivor_plab_arrays() {
  for (uint i = 0; i < ParallelGCThreads; i++) {
    _survivor_plab_array[i].reset();
  }
}
 
//通过构造和析构函数临时修改ReferenceProcessor的span属性
class ReferenceProcessorSpanMutator: StackObj {
 private:
  ReferenceProcessor* _rp;
  MemRegion           _saved_span;
 
 public:
  ReferenceProcessorSpanMutator(ReferenceProcessor* rp,
                                MemRegion span):
    _rp(rp) {
    _saved_span = _rp->span();
    _rp->set_span(span);
  }
 
  ~ReferenceProcessorSpanMutator() {
    _rp->set_span(_saved_span);
  }
};
 
//通过构造和析构函数临时修改ReferenceProcessor的is_alive_non_header属性
class ReferenceProcessorIsAliveMutator: StackObj {
 private:
  ReferenceProcessor* _rp;
  BoolObjectClosure*  _saved_cl;
 
 public:
  ReferenceProcessorIsAliveMutator(ReferenceProcessor* rp,
                                   BoolObjectClosure*  cl):
    _rp(rp) {
    _saved_cl = _rp->is_alive_non_header();
    _rp->set_is_alive_non_header(cl);
  }
 
  ~ReferenceProcessorIsAliveMutator() {
    _rp->set_is_alive_non_header(_saved_cl);
  }
};
 
//通过构造和析构函数临时修改ReferenceProcessor的_processing_is_mt属性
class ReferenceProcessorMTProcMutator: StackObj {
 private:
  ReferenceProcessor* _rp;
  bool  _saved_mt;
 
 public:
  ReferenceProcessorMTProcMutator(ReferenceProcessor* rp,
                                  bool mt):
    _rp(rp) {
    _saved_mt = _rp->processing_is_mt();
    _rp->set_mt_processing(mt);
  }
 
  ~ReferenceProcessorMTProcMutator() {
    _rp->set_mt_processing(_saved_mt);
  }
};
 
//通过构造和析构函数临时修改ReferenceProcessor的discovery_is_atomic属性
class ReferenceProcessorAtomicMutator: StackObj {
 private:
  ReferenceProcessor* _rp;
  bool                _saved_atomic_discovery;
 
 public:
  ReferenceProcessorAtomicMutator(ReferenceProcessor* rp,
                                  bool atomic):
    _rp(rp) {
    _saved_atomic_discovery = _rp->discovery_is_atomic();
    _rp->set_atomic_discovery(atomic);
  }
 
  ~ReferenceProcessorAtomicMutator() {
    _rp->set_atomic_discovery(_saved_atomic_discovery);
  }
};
 
//通过构造和析构函数临时修改ReferenceProcessor的discovery_is_mt属性
class ReferenceProcessorMTDiscoveryMutator: StackObj {
 private:
  ReferenceProcessor* _rp;
  bool                _saved_mt;
 
 public:
  ReferenceProcessorMTDiscoveryMutator(ReferenceProcessor* rp,
                                       bool mt):
    _rp(rp) {
    _saved_mt = _rp->discovery_is_mt();
    _rp->set_mt_discovery(mt);
  }
 
  ~ReferenceProcessorMTDiscoveryMutator() {
    _rp->set_mt_discovery(_saved_mt);
  }
};

调用链如下:

image.png

3、do_mark_sweep_work
do_mark_sweep_work是不需要老年代空间压缩时执行标记清理等垃圾回收动作的入口,核心实现根据GC的步骤放在每个步骤对应的方法中,do_mark_sweep_work负责根据_collectorState状态值调用对应的步骤方法。其实现如下:

void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
  CollectorState first_state, bool should_start_over) {
  if (PrintGC && Verbose) {
    gclog_or_tty->print_cr("Pass concurrent collection to foreground "
      "collector with count %d",
      _full_gcs_since_conc_gc);
  }
  switch (_collectorState) {
    case Idling:
      //如果first_state是Idling,则表明未开始GC,将状态流转成InitialMarking
      //如果should_start_over为true,表示需要重新开始,无论之前是什么状态,都流转成InitialMarking
      if (first_state == Idling || should_start_over) {
        _collectorState = InitialMarking;
      }
      break;
    case Precleaning:
      //如果后台GC已经执行完了Precleaning步骤,则将状态流程成FinalMarking
      _collectorState = FinalMarking;
  }
  collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause());
 
  //compute_new_size方法会被上层的do_collection方法调用
}
 
void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {
  //校验_foregroundGCIsActive为true,_foregroundGCShouldWait为false,即当前方法是前台GC调用的
  assert(_foregroundGCIsActive && !_foregroundGCShouldWait,
         "Foreground collector should be waiting, not executing");
  //校验当前线程是VMThread       
  assert(Thread::current()->is_VM_thread(), "A foreground collection"
    "may only be done by the VM Thread with the world stopped");
  //校验VMThread获取了CMS Token
  assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
         "VM thread should have CMS token");
 
  //生成GC ID
  const GCId gc_id = _collectorState == InitialMarking ? GCId::peek() : _gc_tracer_cm->gc_id();
 
  if (UseAdaptiveSizePolicy) {
    //通知ms_collection 开始,ms是Mark-Sweep的缩写
    size_policy()->ms_collection_begin();
  }
  COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact);
 
  HandleMark hm;  // Discard invalid handles created during verification
 
  if (VerifyBeforeGC &&
      GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
    Universe::verify();
  }
 
  //设置回收策略
  ref_processor()->setup_policy(clear_all_soft_refs);
 
  //判断是否需要卸载Class
  update_should_unload_classes();
 
  bool init_mark_was_synchronous = false; // until proven otherwise
  //通过while循环在不同的状态间流转,直到GC结束,状态变成Idling
  while (_collectorState != Idling) {
    if (TraceCMSState) {
      gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d",
        Thread::current(), _collectorState);
    }
    switch (_collectorState) {
      case InitialMarking:
        //通知GC开始
        register_foreground_gc_start(cause);
        init_mark_was_synchronous = true;  // fact to be exploited in re-mark
        //检查老年代以外的对象指向老年代的引用,执行完成将_collectorState置为Marking
        checkpointRootsInitial(false);
        assert(_collectorState == Marking, "Collector state should have changed"
          " within checkpointRootsInitial()");
        break;
      case Marking:
        if (VerifyDuringGC &&
            GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
          Universe::verify("Verify before initial mark: ");
        }
        {
          //从根节点开始标记存活对象
          bool res = markFromRoots(false);
          assert(res && _collectorState == FinalMarking, "Collector state should "
            "have changed");
          break;
        }
      case FinalMarking:
        if (VerifyDuringGC &&
            GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
          Universe::verify("Verify before re-mark: ");
        }
        //再次检查指向老年代对象的引用
        checkpointRootsFinal(false, clear_all_soft_refs,
                             init_mark_was_synchronous);
        assert(_collectorState == Sweeping, "Collector state should not "
          "have changed within checkpointRootsFinal()");
        break;
      case Sweeping:
        if (VerifyDuringGC &&
            GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
          Universe::verify("Verify before sweep: ");
        }
        //执行清理
        sweep(false);
        assert(_collectorState == Resizing, "Incorrect state");
        break;
      case Resizing: {
        //调整大小就是执行compute_new_size方法,在其他地方执行,所以此处不做啥
        //直接将状态置为Resetting
        _collectorState = Resetting;
        break;
      }
      case Resetting:
        if (VerifyDuringGC &&
            GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
          Universe::verify("Verify before reset: ");
        }
        //保存GC结束后的堆内存和元空间的使用情况
        save_heap_summary();
        //CMSCollector重置,该方法会通知计时器等GC结束
        reset(false);
        assert(_collectorState == Idling, "Collector state should "
          "have changed");
        break;
      case Precleaning:
      case AbortablePreclean:
        // Elide the preclean phase
        _collectorState = FinalMarking;
        break;
      default:
        ShouldNotReachHere();
    }
    if (TraceCMSState) {
      gclog_or_tty->print_cr("  Thread " INTPTR_FORMAT " done - next CMS state %d",
        Thread::current(), _collectorState);
    }
  }
 
  if (UseAdaptiveSizePolicy) {
    GenCollectedHeap* gch = GenCollectedHeap::heap();
    //通知GC结束
    size_policy()->ms_collection_end(gch->gc_cause());
  }
 
  if (VerifyAfterGC &&
      GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
    Universe::verify();
  }
  if (TraceCMSState) {
    gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
      " exiting collection CMS state %d",
      Thread::current(), _collectorState);
  }
}
 
void CMSCollector::update_should_unload_classes() {
  _should_unload_classes = false;
  //ExplicitGCInvokesConcurrentAndUnloadsClasses表示通过System.gc方法触发GC时是否卸载Class,默认为false
  if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) {
    _should_unload_classes = true;
  } else if (CMSClassUnloadingEnabled) { // CMSClassUnloadingEnabled表示CMS GC时是否允许Class卸载
    //CMSClassUnloadingMaxInterval表示一个阈值,如果自上一次Class卸载后GC的次数超过该值则执行Class卸载
    _should_unload_classes = (concurrent_cycles_since_last_unload() >=
                              CMSClassUnloadingMaxInterval)
                           || _cmsGen->is_too_full();
  }
}
 
 unsigned int concurrent_cycles_since_last_unload() const {
    return _concurrent_cycles_since_last_unload;
  }
 
void CMSCollector::register_foreground_gc_start(GCCause::Cause cause) {
  if (!_cms_start_registered) {
    //通知GC开始
    register_gc_start(cause);
  }
}
 
void CMSCollector::register_gc_start(GCCause::Cause cause) {
  _cms_start_registered = true;
  _gc_timer_cm->register_gc_start();
  _gc_tracer_cm->report_gc_start(cause, _gc_timer_cm->gc_start());
}

其调用如下:


image.png

4、collect_in_background
collect_in_background用于CMSThread触发的后台垃圾回收,其实现如下:

void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) {
  assert(Thread::current()->is_ConcurrentGC_thread(),
    "A CMS asynchronous collection is only allowed on a CMS thread.");
 
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  {
    bool safepoint_check = Mutex::_no_safepoint_check_flag;
    //获取Heap_lock锁
    MutexLockerEx hl(Heap_lock, safepoint_check);
    //获取FreelistLock锁
    FreelistLocker fll(this);
    //获取CGC_lock锁
    MutexLockerEx x(CGC_lock, safepoint_check);
    //UseAsyncConcMarkSweepGC表示是否使用异步的垃圾回收,默认为true
    if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) {
      //如果前台GC正在执行,则退出
      assert(!_foregroundGCShouldWait, "Should be clear");
      return;
    } else {
      assert(_collectorState == Idling, "Should be idling before start.");
      //将_collectorState由Idling改为InitialMarking
      _collectorState = InitialMarking;
      //通知GC开始
      register_gc_start(cause);
      //清除扩展原因
      clear_expansion_cause();
      //元空间的GC标识置为false
      MetaspaceGC::set_should_concurrent_collect(false);
    }
    //判断是否需要卸载Class
    update_should_unload_classes();
    //后台GC触发的GC,所以将_full_gc_requested置为false
    _full_gc_requested = false;           // acks all outstanding full gc requests
    _full_gc_cause = GCCause::_no_gc;
    //增加总的GC次数
    gch->increment_total_full_collections();  // ... starting a collection cycle
    _collection_count_start = gch->total_full_collections();
  }
 
  // Used for PrintGC
  size_t prev_used = 0;
  if (PrintGC && Verbose) {
    //GC开始前的内存使用量
    prev_used = _cmsGen->used(); // XXXPERM
  }
 
  while (_collectorState != Idling) {
    if (TraceCMSState) {
      gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d",
        Thread::current(), _collectorState);
    }
 
    {
      //获取CMS Token
      CMSTokenSync x(true); // is cms thread
      //如果前台GC在进行中,则不断循环等待GC结束,然后返回true
      //返回false表示没有执行前台GC
      if (waitForForegroundGC()) {
        //前台GC完成了,不需要再进行后台GC了,直接返回
        assert(_foregroundGCShouldWait == false, "We set it to false in "
               "waitForForegroundGC()");
        if (TraceCMSState) {
          gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
            " exiting collection CMS state %d",
            Thread::current(), _collectorState);
        }
        return;
      } else {
        //检查_collectorState,正常不会是Idling,因为执行后台GC只有一个线程,CMSThread
        if (_collectorState == Idling) {
          break;
        }
      }
    }
    
    //waitForForegroundGC方法中将该标志置为true,表示开始执行后台GC
    assert(_foregroundGCShouldWait, "Foreground collector, if active, "
      "should be waiting");
 
    switch (_collectorState) {
      case InitialMarking:
        {
          //检查前台GC是否开始,如果开始则让出执行权限
          ReleaseForegroundGC x(this);
          //记录GC开始
          stats().record_cms_begin();
          //通过VMThread执行InitialMarking步骤,底层还是调用checkpointRootsInitial方法
          VM_CMS_Initial_Mark initial_mark_op(this);
          VMThread::execute(&initial_mark_op);
        }
        break;
      case Marking:
        //从根节点标记
        if (markFromRoots(true)) { // we were successful
          assert(_collectorState == Precleaning, "Collector state should "
            "have changed");
        } else {
          assert(_foregroundGCIsActive, "Internal state inconsistency");
        }
        break;
      case Precleaning:
        if (UseAdaptiveSizePolicy) {
          //记录preclean开始
          size_policy()->concurrent_precleaning_begin();
        }
        //执行预清理
        preclean();
        if (UseAdaptiveSizePolicy) {
          //记录preclean结束
          size_policy()->concurrent_precleaning_end();
        }
        assert(_collectorState == AbortablePreclean ||
               _collectorState == FinalMarking,
               "Collector state should have changed");
        break;
      case AbortablePreclean:
        if (UseAdaptiveSizePolicy) {
        size_policy()->concurrent_phases_resume();
        }
        //执行可终止的清理
        abortable_preclean();
        if (UseAdaptiveSizePolicy) {
          size_policy()->concurrent_precleaning_end();
        }
        assert(_collectorState == FinalMarking, "Collector state should "
          "have changed");
        break;
      case FinalMarking:
        {
          //检查前台GC是否开始,如果开始则让出执行权限
          ReleaseForegroundGC x(this); 
          //通过VMThread执行最终标记,底层是调用checkpointRootsFinal方法
          VM_CMS_Final_Remark final_remark_op(this);
          VMThread::execute(&final_remark_op);
        }
        assert(_foregroundGCShouldWait, "block post-condition");
        break;
      case Sweeping:
        if (UseAdaptiveSizePolicy) {
          //记录sweep开始
          size_policy()->concurrent_sweeping_begin();
        }
        //执行清理
        sweep(true);
        assert(_collectorState == Resizing, "Collector state change "
          "to Resizing must be done under the free_list_lock");
        _full_gcs_since_conc_gc = 0;
 
        // Stop the timers for adaptive size policy for the concurrent phases
        if (UseAdaptiveSizePolicy) {
           //记录sweep结束
          size_policy()->concurrent_sweeping_end();
          size_policy()->concurrent_phases_end(gch->gc_cause(),
                                             gch->prev_gen(_cmsGen)->capacity(),
                                             _cmsGen->free());
        }
 
      case Resizing: {
        {
          //检查前台GC是否开始
          ReleaseForegroundGC x(this);   // unblock FG collection
          //获取锁
          MutexLockerEx       y(Heap_lock, Mutex::_no_safepoint_check_flag);
          CMSTokenSync        z(true);   // not strictly needed.
          if (_collectorState == Resizing) {
            //重新计算容量
            compute_new_size();
            //保存堆内存使用情况
            save_heap_summary();
            //修改状态
            _collectorState = Resetting;
          } else {
            assert(_collectorState == Idling, "The state should only change"
                   " because the foreground collector has finished the collection");
          }
        }
        break;
      }
      case Resetting:
        //重置CMSCollector的状态
        reset(true);
        assert(_collectorState == Idling, "Collector state should "
          "have changed");
        MetaspaceGC::set_should_concurrent_collect(false);
        stats().record_cms_end();
        
        break;
      case Idling:
      default:
        ShouldNotReachHere();
        break;
    }
    if (TraceCMSState) {
      gclog_or_tty->print_cr("  Thread " INTPTR_FORMAT " done - next CMS state %d",
        Thread::current(), _collectorState);
    }
    assert(_foregroundGCShouldWait, "block post-condition");
  }
 
  //更新计数器
  collector_policy()->counters()->update_counters();
 
  {
    //获取锁CGC_lock
    MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
    _foregroundGCShouldWait = false;
    if (_foregroundGCIsActive) {
      //让出使用权限
      CGC_lock->notify();
    }
    assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
           "Possible deadlock");
  }
  if (TraceCMSState) {
    gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
      " exiting collection CMS state %d",
      Thread::current(), _collectorState);
  }
  if (PrintGC && Verbose) {
    _cmsGen->print_heap_change(prev_used);
  }
}
 
//如果前台GC开始了则不断循环等待,直到前台GC完成
bool CMSCollector::waitForForegroundGC() {
  bool res = false;
  //校验已经获取了CMS Token
  assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
         "CMS thread should have CMS token");
  //获取锁CGC_lock
  MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
  _foregroundGCShouldWait = true;
  if (_foregroundGCIsActive) {
    //如果前台GC在执行中,则让出执行权限
    res = true;
    _foregroundGCShouldWait = false;
    //释放CMS Token
    ConcurrentMarkSweepThread::clear_CMS_flag(
      ConcurrentMarkSweepThread::CMS_cms_has_token);
    ConcurrentMarkSweepThread::set_CMS_flag(
      ConcurrentMarkSweepThread::CMS_cms_wants_token);
    //唤醒CGC_lock上等待的线程,从而前台GC可获取CMS Token
    CGC_lock->notify();
    if (TraceCMSState) {
      gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " waiting at CMS state %d",
        Thread::current(), _collectorState);
    }
    //不断循环等待直到_foregroundGCIsActive变成false,即前台GC结束
    while (_foregroundGCIsActive) {
      CGC_lock->wait(Mutex::_no_safepoint_check_flag);
    }
    //等待结束,前台GC完成,设置CMS_flag,表示已获取CMS Token
    ConcurrentMarkSweepThread::set_CMS_flag(
      ConcurrentMarkSweepThread::CMS_cms_has_token);
    ConcurrentMarkSweepThread::clear_CMS_flag(
      ConcurrentMarkSweepThread::CMS_cms_wants_token);
  }
  if (TraceCMSState) {
    gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT " continuing at CMS state %d",
      Thread::current(), _collectorState);
  }
  return res;
}

上述代码中的FreelistLocker用于获取FreelistLock,其定义如下:

image.png

ReleaseForegroundGC用于检查前台GC是否触发,如果触发了则唤醒在CGC_lock上等待的VMThread,方便其进入安全点,从而达到stop the world的目标,其定义如下:

image.png

注意这里无论_foregroundGCIsActive是否为true,都将_foregroundGCShouldWait置为了false,这是因为后台GC在执行initial mark, final remark这两个步骤时需要stop the world,停止所有其他线程的执行,为了避免执行前台GC的VMThread因为 _foregroundGCShouldWait 处于阻塞状态而无法进入到安全点而导致无法达到stop the world的效果,所以这里临时将_foregroundGCShouldWait置为false,等initial mark或者final remark执行完成就将_foregroundGCShouldWait置为true。

5、VM_CMS_Operation
VM_CMS_Operation是后面两个类的父类,其类继承关系如下:

image.png

VM_Operation的实现参考VM_Operation 源码解析,VM_CMS_Operation增加了两个属性:

重点关注其doit_prologue和doit_epilogue方法的实现,这两方法是doit执行前后调用的方法,VM_CMS_Operation未提供doit方法的默认实现,注意这两方法都是由调用VMThread::execute的CMSThread线程执行的,VMThread只负责执行doit方法,如下:

 
VM_CMS_Operation(CMSCollector* collector):
    _collector(collector),
    _prologue_succeeded(false) {}
 
bool VM_CMS_Operation::doit_prologue() {
  //校验当前线程是CMS Thread
  assert(Thread::current()->is_ConcurrentGC_thread(), "just checking");
  //校验foregroundGCShouldWait属性为false,在ReleaseForegroundGC的构造方法中将该属性置为false
  assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock");
  //前台GC未执行,所以不需要跟执行前台GC的VTThread通过CMS Token同步,cms_thread_has_cms_token就返回false
  assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
         "Possible deadlock");
  
  //如果需要PLL锁
  if (needs_pll()) {
    //获取锁
    acquire_pending_list_lock();
  }
  //获取Heap_lock锁
  Heap_lock->lock();
  if (lost_race()) {
    //如果其他线程已经完成GC,则释放Heap_lock,PLL锁
    assert(_prologue_succeeded == false, "Initialized in c'tor");
    Heap_lock->unlock();
    if (needs_pll()) {
      release_and_notify_pending_list_lock();
    }
  } else {
   //将_prologue_succeeded置为true,默认为false
    _prologue_succeeded = true;
  }
  return _prologue_succeeded;
}
 
void VM_CMS_Operation::acquire_pending_list_lock() {
  //PLL就是pending list lock的简称,底层实际就是一个偏向锁BasicLock
  SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt();
  if (slt != NULL) {
    //获取PLL锁
    slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
  } else {
    SurrogateLockerThread::report_missing_slt();
  }
}
 
bool VM_CMS_Operation::lost_race() const {
  if (CMSCollector::abstract_state() == CMSCollector::Idling) {
    //校验_collectorState状态,如果是Idling说明已经完成GC
    return true;
  }
  //校验状态是否正确,legal_state方法返回当前Operation支持的正确状态
  assert(CMSCollector::abstract_state() == legal_state(),
         "Inconsistent collector state?");
  return false;
}
 
static CollectorState abstract_state() { return _collectorState;  }
 
void VM_CMS_Operation::release_and_notify_pending_list_lock() {
  ConcurrentMarkSweepThread::slt()->
    manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
}
 
 
void VM_CMS_Operation::doit_epilogue() {
  assert(Thread::current()->is_ConcurrentGC_thread(), "just checking");
  assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock");
  assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
         "Possible deadlock");
 
  //释放Heap_lock,PLL锁
  Heap_lock->unlock();
  if (needs_pll()) {
    release_and_notify_pending_list_lock();
  }
}

6、VM_CMS_Initial_Mark / VM_CMS_Final_Remark
这两个都继承自VM_CMS_Operation,分别用来执行CMS_Initial_Mark和CMS_Final_Remark任务,重点关注其doit方法的实现,其底层核心实现跟collect_in_foreground中同样步骤的实现是一样的,如下:

virtual const CMSCollector::CollectorState legal_state() const {
    return CMSCollector::InitialMarking;
  }
 
virtual const bool needs_pll() const {
    return false;
  }
 
void VM_CMS_Initial_Mark::doit() {
  if (lost_race()) {
    //如果GC已完成
    return;
  }
  //通知GC中断开始,即中断CMS Thread的GC,转交给VMThread执行
  _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark");
 
  //设置gc_cause
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  GCCauseSetter gccs(gch, GCCause::_cms_initial_mark);
 
  VM_CMS_Operation::verify_before_gc();
  
  //将CollectedHeap的_is_gc_active属性置true
  IsGCActiveMark x; // stop-world GC active
  //执行具体的GC逻辑
  _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause());
 
  VM_CMS_Operation::verify_after_gc();
  //通知GC中断结束,GC即将转交给CMSThread继续执行
  _collector->_gc_timer_cm->register_gc_pause_end();
 
}
 
 virtual const CMSCollector::CollectorState legal_state() const {
    return CMSCollector::FinalMarking;
  }
 
  virtual const bool needs_pll() const {
    return true;
  }
 
//代码逻辑跟VM_CMS_Initial_Mark基本一致
void VM_CMS_Final_Remark::doit() {
  if (lost_race()) {
    // Nothing to do.
    return;
  }
 
  _collector->_gc_timer_cm->register_gc_pause_start("Final Mark");
 
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  GCCauseSetter gccs(gch, GCCause::_cms_final_remark);
 
  VM_CMS_Operation::verify_before_gc();
 
  IsGCActiveMark x; // stop-world GC active
  _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause());
 
  VM_CMS_Operation::verify_after_gc();
 
  _collector->save_heap_summary();
  _collector->_gc_timer_cm->register_gc_pause_end();
 
}
 
void VM_CMS_Operation::verify_before_gc() {
  //VerifyBeforeGC表示是否需要在GC前执行校验逻辑,默认为false
  if (VerifyBeforeGC &&
      GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
    GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id());
    HandleMark hm;
    FreelistLocker x(_collector);
    MutexLockerEx  y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
    Universe::heap()->prepare_for_verify();
    Universe::verify();
  }
}
 
void VM_CMS_Operation::verify_after_gc() {
  if (VerifyAfterGC &&
      GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
    GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id());
    HandleMark hm;
    FreelistLocker x(_collector);
    MutexLockerEx  y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
    Universe::verify();
  }
}
 
void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) {
  TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
  GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer_cm->gc_id());
  TraceCollectorStats tcs(counters());
 
  //根据CMS_op_type执行不同的逻辑
  switch (op) {
    case CMS_op_checkpointRootsInitial: {
      SvcGCMarker sgcm(SvcGCMarker::OTHER);
      checkpointRootsInitial(true);       // asynch
      if (PrintGC) {
        _cmsGen->printOccupancy("initial-mark");
      }
      break;
    }
    case CMS_op_checkpointRootsFinal: {
      SvcGCMarker sgcm(SvcGCMarker::OTHER);
      checkpointRootsFinal(true,    // asynch
                           false,   // !clear_all_soft_refs
                           false);  // !init_mark_was_synchronous
      if (PrintGC) {
        _cmsGen->printOccupancy("remark");
      }
      break;
    }
    default:
      fatal("No such CMS_op");
  }
}

上述代码中IsGCActiveMark类用来临时将CollectedHeap的_is_gc_active属性置true,其定义如下:

image.png

SvcGCMarker用来通知GC开始和结束,notify_gc_begin和notify_gc_end实际就是打日志而已,其定义如下:

image.png

7、shouldConcurrentCollect
该方法由CMSThread调用,用来判断是否需要执行GC,如果需要则调用collect_in_background方法执行GC,其实现如下:

bool CMSCollector::shouldConcurrentCollect() {
  if (_full_gc_requested) {
    //如果需要full GC
    if (Verbose && PrintGCDetails) {
      gclog_or_tty->print_cr("CMSCollector: collect because of explicit "
                             " gc request (or gc_locker)");
    }
    return true;
  }
  
  //获取FreelistLock锁
  FreelistLocker x(this);
 
  //打印老年代的内存使用情况
  if (PrintCMSInitiationStatistics && stats().valid()) {
    gclog_or_tty->print("CMSCollector shouldConcurrentCollect: ");
    gclog_or_tty->stamp();
    gclog_or_tty->cr();
    stats().print_on(gclog_or_tty);
    gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f",
      stats().time_until_cms_gen_full());
    gclog_or_tty->print_cr("free=" SIZE_FORMAT, _cmsGen->free());
    gclog_or_tty->print_cr("contiguous_available=" SIZE_FORMAT,
                           _cmsGen->contiguous_available());
    gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
    gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
    gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy());
    gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());
    gclog_or_tty->print_cr("cms_time_since_begin=%3.7f", stats().cms_time_since_begin());
    gclog_or_tty->print_cr("cms_time_since_end=%3.7f", stats().cms_time_since_end());
    gclog_or_tty->print_cr("metadata initialized %d",
      MetaspaceGC::should_concurrent_collect());
  }
  // ------------------------------------------------------------------
 
  //UseCMSInitiatingOccupancyOnly表示是否只使用InitiatingOccupancy作为判断是否GC的标准,默认为false
  if (!UseCMSInitiatingOccupancyOnly) {
    //如果CMSStas的数据是有效的
    if (stats().valid()) {
      //如果当前时间与上一次垃圾回收的时间间隔超过了历史上的时间间隔
      if (stats().time_until_cms_start() == 0.0) {
        return true;
      }
    } else {
      //判断使用率是否超过设定的值
      if (_cmsGen->occupancy() >= _bootstrap_occupancy) {
        if (Verbose && PrintGCDetails) {
          gclog_or_tty->print_cr(
            " CMSCollector: collect for bootstrapping statistics:"
            " occupancy = %f, boot occupancy = %f", _cmsGen->occupancy(),
            _bootstrap_occupancy);
        }
        return true;
      }
    }
  }
 
  //cmsGen认为应该GC
  if (_cmsGen->should_concurrent_collect()) {
    if (Verbose && PrintGCDetails) {
      gclog_or_tty->print_cr("CMS old gen initiated");
    }
    return true;
  }
 
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  assert(gch->collector_policy()->is_two_generation_policy(),
         "You may want to check the correctness of the following");
  //如果增量收集会失败       
  if (gch->incremental_collection_will_fail(true /* consult_young */)) {
    if (Verbose && PrintGCDetails) {
      gclog_or_tty->print("CMSCollector: collect because incremental collection will fail ");
    }
    return true;
  }
  //如果元空间需要GC
  if (MetaspaceGC::should_concurrent_collect()) {
    if (Verbose && PrintGCDetails) {
      gclog_or_tty->print("CMSCollector: collect for metadata allocation ");
    }
    return true;
  }
 
  // CMSTriggerInterval表示CMS触发的间隔时间,默认值是-1
  if (CMSTriggerInterval >= 0) {
    if (CMSTriggerInterval == 0) {
      //如果等于0,表示每次都触发
      return true;
    }
 
    //否则检测当前时间与上一次GC的时间间隔是否超过限制
    if (stats().cms_time_since_begin() >= (CMSTriggerInterval / ((double) MILLIUNITS))) {
      if (Verbose && PrintGCDetails) {
        if (stats().valid()) {
          gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (time since last begin %3.7f secs)",
                                 stats().cms_time_since_begin());
        } else {
          gclog_or_tty->print_cr("CMSCollector: collect because of trigger interval (first collection)");
        }
      }
      return true;
    }
  }
 
  return false;
}

8、总结
CMS下触发GC的有两种方式,一种是同步的,内存分配失败或者调用System.gc()方法会触发同步的GC,GC的具体步骤会由VMThread执行完成,也成前台GC(foreground GC);一种是异步的,CMSThread在后台会按照一定的规则不断的轮询判断是否需要GC,如果需要则执行GC,也成后台GC(background GC)不过有两个步骤initial mark, final remark,需要stop the world后才能执行,CMSThread在执行这两个步骤时会将其转交给VMThread执行。

为了保证VMThread和CMS Thread不会并行的执行GC,就需要在两者之间做同步,主要通过_foregroundGCIsActive和_foregroundGCShouldWait,CGC_lock来实现的,_foregroundGCIsActive为true表示前台GC被触发了,如果此时_foregroundGCShouldWait为true则表示后台GC正在执行某个GC步骤,执行前台GC的VMThead会在CGC_lock上不断轮询等待直到_foregroundGCShouldWait变为false,等待结束后会根据当前GC的状态_collectorState来决定执行下一个步骤,大部分情况下会继续处理后台GC的剩余步骤,但是需要清理所有软引用且老年代不需要压缩且FinalMarking步骤完成了,则需要重新开启一轮新的GC,重新查找待处理的Reference实例。等前台GC结束后会将_foregroundGCIsActive置为false。

后台GC开始执行时会检查_foregroundGCIsActive是否为true,如果是则返回;如果是false,则开始循环处理GC的各个步骤,每次循环前都要检查_foregroundGCIsActive是否为true,如果为true,则_foregroundGCShouldWait置为false,然后在CGC_lock上等待直到_foregroundGCIsActive变成false,即等待前台GC结束,然后返回;如果为false,则将_foregroundGCShouldWait属性置为true,开始处理下一个步骤。有两个步骤比较特殊,initial mark, final remark,在开始执行时还会再检查一遍_foregroundGCIsActive是否为true,如果为true,则将在CGC_lock上等待的VMThread唤醒,方便其进入安全点,达到stop the world的目的。

上一篇 下一篇

猜你喜欢

热点阅读