Top


定義場所(file name)

hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp

名前(function name)

void G1CollectedHeap::evacuate_collection_set() {

本体部(body)

  {- -------------------------------------------
  (1) GC 開始前に _evacuation_failed フィールドを初期化しておく.
      ---------------------------------------- -}

      set_evacuation_failed(false);

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      g1_rem_set()->prepare_for_oops_into_collection_set_do();

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      concurrent_g1_refine()->set_use_cache(false);
      concurrent_g1_refine()->clear_hot_cache_claimed_index();

  {- -------------------------------------------
  (1) G1CollectedHeap::set_par_threads() で
      使用する GC スレッド数を登録しておく.
      ---------------------------------------- -}

      int n_workers = (ParallelGCThreads > 0 ? workers()->total_workers() : 1);
      set_par_threads(n_workers);

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      G1ParTask g1_par_task(this, n_workers, _task_queues);

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      init_for_evac_failure(NULL);

      rem_set()->prepare_for_younger_refs_iterate(true);

  {- -------------------------------------------
  (1) (assert)
      ---------------------------------------- -}

      assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");

  {- -------------------------------------------
  (1) (変数宣言など)
      (GC 開始時の時刻を記録しておく)
      ---------------------------------------- -}

      double start_par = os::elapsedTime();

  {- -------------------------------------------
  (1) 実際の GC 処理を行う.
      (複数スレッドを使用して並列に行うなら(= G1CollectedHeap::use_parallel_gc_threads() が true なら), WorkGang::run_task() で G1ParTask を並列実行する.
       そうでなければ, 直接 G1ParTask::work() を呼び出すだけ.)
      ---------------------------------------- -}

      if (G1CollectedHeap::use_parallel_gc_threads()) {
        // The individual threads will set their evac-failure closures.
        StrongRootsScope srs(this);
        if (ParallelGCVerbose) G1ParScanThreadState::print_termination_stats_hdr();
        workers()->run_task(&g1_par_task);
      } else {
        StrongRootsScope srs(this);
        g1_par_task.work(0);
      }

  {- -------------------------------------------
  (1) GC に掛かった時間を計算し, g1_policy()->record_par_time() で g1_policy() 内に記録.
      ---------------------------------------- -}

      double par_time = (os::elapsedTime() - start_par) * 1000.0;
      g1_policy()->record_par_time(par_time);

  {- -------------------------------------------
  (1) G1CollectedHeap::set_par_threads() で, GC スレッド数情報をリセットしておく.
      ---------------------------------------- -}

      set_par_threads(0);

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      // Is this the right thing to do here?  We don't save marks
      // on individual heap regions when we allocate from
      // them in parallel, so this seems like the correct place for this.
      retire_all_alloc_regions();

  {- -------------------------------------------
  (1) Weak global JNI references に対して処理を行う.
      ---------------------------------------- -}

      // Weak root processing.
      // Note: when JSR 292 is enabled and code blobs can contain
      // non-perm oops then we will need to process the code blobs
      // here too.
      {
        G1IsAliveClosure is_alive(this);
        G1KeepAliveClosure keep_alive(this);
        JNIHandles::weak_oops_do(&is_alive, &keep_alive);
      }

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      release_gc_alloc_regions(false /* totally */);
      g1_rem_set()->cleanup_after_oops_into_collection_set_do();

      concurrent_g1_refine()->clear_hot_cache();
      concurrent_g1_refine()->set_use_cache(true);

      finalize_for_evac_failure();

      // Must do this before removing self-forwarding pointers, which clears
      // the per-region evac-failure flags.
      concurrent_mark()->complete_marking_in_collection_set();

  {- -------------------------------------------
  (1) Minor GC が途中で失敗していた場合, 
      G1CollectedHeap::remove_self_forwarding_pointers() を呼んで
      コピーに失敗したオブジェクトの後始末処理を行う
      (markbit に生きていると印をつける, 
      そのオブジェクト内のポインタフィールドから指されている先の Remembered Set を修正する, 
      saved mark を戻す, 
      etc)

      (ついでに(トレース出力)も出している)
      ---------------------------------------- -}

      if (evacuation_failed()) {
        remove_self_forwarding_pointers();
        if (PrintGCDetails) {
          gclog_or_tty->print(" (to-space overflow)");
        } else if (PrintGC) {
          gclog_or_tty->print("--");
        }
      }

  {- -------------------------------------------
  (1) G1CollectedHeap::dirty_card_queue_set() 内の各 card について 
      (= 処理が遅延されていた各 card について), 
      card の dirty 化を行い, JavaThread クラスの _dirty_card_queue_set フィールドにマージしておく.

      (ただし develop オプションである G1DeferredRSUpdate がセットされている場合は何もしない)
      ---------------------------------------- -}

      if (G1DeferredRSUpdate) {
        RedirtyLoggedCardTableEntryFastClosure redirty;
        dirty_card_queue_set().set_closure(&redirty);
        dirty_card_queue_set().apply_closure_to_all_completed_buffers();

        DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set();
        dcq.merge_bufferlists(&dirty_card_queue_set());
        assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
      }

  {- -------------------------------------------
  (1) #ifdef COMPILER2 の場合には, GC が終わったので
      見つかった derived pointer の値を修正しておく.
      (See: DerivedPointerTable)
      ---------------------------------------- -}

      COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.