Top


定義場所(file name)

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

名前(function name)

void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp,
  bool clear_all_softrefs) {

本体部(body)

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

      assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");

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

      GenCollectedHeap* gch = GenCollectedHeap::heap();

  {- -------------------------------------------
  (1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
      ---------------------------------------- -}

    #ifdef ASSERT
      if (gch->collector_policy()->should_clear_all_soft_refs()) {
        assert(clear_all_softrefs, "Policy should have been checked earlier");
      }
    #endif

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

      // hook up weak ref data so it can be used during Mark-Sweep
      assert(ref_processor() == NULL, "no stomping");
      assert(rp != NULL, "should be non-NULL");

  {- -------------------------------------------
  (1) rp 引数で渡された ReferenceProcessor を GenMarkSweep::_ref_processor フィールドに格納し, 
      ついでに ReferenceProcessor::setup_policy() を呼んで初期化もしておく.
      ---------------------------------------- -}

      _ref_processor = rp;
      rp->setup_policy(clear_all_softrefs);

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

      TraceTime t1("Full GC", PrintGC && !PrintGCDetails, true, gclog_or_tty);

  {- -------------------------------------------
  (1) フレーム中の bcp (byte code pointer, バイトコードを指すポインタ) を格納している箇所については
      GC によって methodOop が移動すると値が不正になってしまうので, 
      Threads::gc_prologue() を呼んで
      フレーム中の bcp を bci (byte code index, そのバイトコードのメソッド先頭からのオフセット値) に変えておく.

      (なお, CodeCache::gc_prologue()の方は, 単なる(assert) (See: CodeCache::gc_prologue()))
      ---------------------------------------- -}

      // When collecting the permanent generation methodOops may be moving,
      // so we either have to flush all bcp data or convert it into bci.
      CodeCache::gc_prologue();
      Threads::gc_prologue();

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

      // Increment the invocation count for the permanent generation, since it is
      // implicitly collected whenever we do a full mark sweep collection.
      gch->perm_gen()->stat_record()->invocations++;

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

      // Capture heap size before collection for printing.
      size_t gch_prev_used = gch->used();

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

      // Some of the card table updates below assume that the perm gen is
      // also being collected.
      assert(level == gch->n_gens() - 1,
             "All generations are being collected, ergo perm gen too.");

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

      // Capture used regions for each generation that will be
      // subject to collection, so that card table adjustments can
      // be made intelligently (see clear / invalidate further below).
      gch->save_used_regions(level, true /* perm */);

  {- -------------------------------------------
  (1) GenMarkSweep::allocate_stacks() を呼んで, mark フィールドの値を待避するための領域を確保しておく.
      (See: PreservedMark)
      ---------------------------------------- -}

      allocate_stacks();

  {- -------------------------------------------
  (1) GenMarkSweep::mark_sweep_phase1() を呼んで, 
      全ての生きているオブジェクト(live object)にマークを付ける.
      ---------------------------------------- -}

      mark_sweep_phase1(level, clear_all_softrefs);

  {- -------------------------------------------
  (1) GenMarkSweep::mark_sweep_phase2() を呼んで, 
      各 live object に対して, コンパクション後の新しいアドレスを forwarding pointer として埋め込む.
      ---------------------------------------- -}

      mark_sweep_phase2();

  {- -------------------------------------------
  (1) #ifdef COMPILER2 の場合には, (これから GC を行うので) DerivedPointerTable の値をリセットしておく.
      (See: DerivedPointerTable)
      ---------------------------------------- -}

      // Don't add any more derived pointers during phase3
      COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity"));
      COMPILER2_PRESENT(DerivedPointerTable::set_active(false));

  {- -------------------------------------------
  (1) GenMarkSweep::mark_sweep_phase3() を呼んで, 各 live object 内のポインタを新しいアドレスに修正する.
      ---------------------------------------- -}

      mark_sweep_phase3(level);

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

      VALIDATE_MARK_SWEEP_ONLY(
        if (ValidateMarkSweep) {
          guarantee(_root_refs_stack->length() == 0, "should be empty by now");
        }
      )

  {- -------------------------------------------
  (1) GenMarkSweep::mark_sweep_phase4() を呼んで, 各 live object を新しいアドレスに移動させる.
      ---------------------------------------- -}

      mark_sweep_phase4();

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

      VALIDATE_MARK_SWEEP_ONLY(
        if (ValidateMarkSweep) {
          guarantee(_live_oops->length() == _live_oops_moved_to->length(),
                    "should be the same size");
        }
      )

  {- -------------------------------------------
  (1) MarkSweep::restore_marks() を呼んで, 
      MarkSweep::preserve_mark() で待避していた mark 値を, 元のオブジェクトの mark フィールドに書き戻す.
      (See: PreservedMark)
      ---------------------------------------- -}

      restore_marks();

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

      // Set saved marks for allocation profiler (and other things? -- dld)
      // (Should this be in general part?)
      gch->save_marks();

  {- -------------------------------------------
  (1) GenMarkSweep::deallocate_stacks() を呼んで, 
      GenMarkSweep::allocate_stacks() で確保した領域を解放する.
      (See: PreservedMark)
      ---------------------------------------- -}

      deallocate_stacks();

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

      // If compaction completely evacuated all generations younger than this
      // one, then we can clear the card table.  Otherwise, we must invalidate
      // it (consider all cards dirty).  In the future, we might consider doing
      // compaction within generations only, and doing card-table sliding.

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

      bool all_empty = true;
      for (int i = 0; all_empty && i < level; i++) {
        Generation* g = gch->get_gen(i);
        all_empty = all_empty && gch->get_gen(i)->used() == 0;
      }
      GenRemSet* rs = gch->rem_set();

    {- -------------------------------------------
  (1.1) 
        ---------------------------------------- -}

      // Clear/invalidate below make use of the "prev_used_regions" saved earlier.
      if (all_empty) {
        // We've evacuated all generations below us.
        Generation* g = gch->get_gen(level);
        rs->clear_into_younger(g, true /* perm */);
      } else {
        // Invalidate the cards corresponding to the currently used
        // region and clear those corresponding to the evacuated region
        // of all generations just collected (i.e. level and younger).
        rs->invalidate_or_clear(gch->get_gen(level),
                                true /* younger */,
                                true /* perm */);
      }

  {- -------------------------------------------
  (1) フレーム中の bcp (byte code pointer, バイトコードを指すポインタ) を格納している箇所については
      GC 前に Threads::gc_prologue() で 
      bcp から bci(byte code index, そのバイトコードのメソッド先頭からのオフセット値) へと値を変更していたので, 
      Threads::gc_epilogue() を呼んで元に戻しておく.
      (ついでに, フレーム内の値について環境依存(プラットフォーム依存)な処理が必要であれば, それも行っている)
      ---------------------------------------- -}

      Threads::gc_epilogue();

  {- -------------------------------------------
  (1) #TODO
      ---------------------------------------- -}

      CodeCache::gc_epilogue();

  {- -------------------------------------------
  (1) JvmtiExport::gc_epilogue() を呼んで, 
      JvmtiBreakpointCache 内でキャッシュしているブレークポイントを指すポインタも更新しておく.
      ---------------------------------------- -}

      JvmtiExport::gc_epilogue();

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

      if (PrintGC && !PrintGCDetails) {
        gch->print_heap_change(gch_prev_used);
      }

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

      // refs processing: clean slate
      _ref_processor = NULL;

  {- -------------------------------------------
  (1) Universe::update_heap_info_at_gc() を呼んで, 
      以下の値を現在のヒープの最大長(capacity)及び使用量(used)に応じた値に変更する.
        * Universe::get_heap_capacity_at_last_gc()
        * Universe::get_heap_free_at_last_gc() 
        * Universe::get_heap_used_at_last_gc()
      なお, これらの値は ReferencePolicy オブジェクト内で soft reference の消去ポリシーの決定に使用されている.
      (See: ReferencePolicy)
      ---------------------------------------- -}

      // Update heap occupancy information which is used as
      // input to soft ref clearing policy at the next gc.
      Universe::update_heap_info_at_gc();

  {- -------------------------------------------
  (1) GenCollectedHeap::update_time_of_last_gc() を呼び出して, 
      全ての Generation の _time_of_last_gc フィールドを現在時刻に更新しておく.
      (これは sun.misc.GC.maxObjectInspectionAge() メソッドを実現するため(だけ)の処理.
       See: JVM_MaxObjectInspectionAge())
      ---------------------------------------- -}

      // Update time of last gc for all generations we collected
      // (which curently is all the generations in the heap).
      gch->update_time_of_last_gc(os::javaTimeMillis());
    }

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