Top


定義場所(file name)

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

名前(function name)

void GenCollectedHeap::do_collection(bool  full,
                                     bool   clear_all_soft_refs,
                                     size_t size,
                                     bool   is_tlab,
                                     int    max_level) {

本体部(body)

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

      bool prepared_for_verification = false;
      ResourceMark rm;
      DEBUG_ONLY(Thread* my_thread = Thread::current();)

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

      assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
      assert(my_thread->is_VM_thread() ||
             my_thread->is_ConcurrentGC_thread(),
             "incorrect thread type capability");
      assert(Heap_lock->is_locked(),
             "the requesting thread should have the Heap_lock");
      guarantee(!is_gc_active(), "collection is not reentrant");
      assert(max_level < n_gens(), "sanity check");

  {- -------------------------------------------
  (1) もし GC_locker によって GC が禁止されていれば, ここでリターン.
      ---------------------------------------- -}

      if (GC_locker::check_active_before_gc()) {
        return; // GC is disabled (e.g. JNI GetXXXCritical operation)
      }

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

      const bool do_clear_all_soft_refs = clear_all_soft_refs ||
                              collector_policy()->should_clear_all_soft_refs();

      ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());

      const size_t perm_prev_used = perm_gen()->used();

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

      if (PrintHeapAtGC) {
        Universe::print_heap_before_gc();
        if (Verbose) {
          gclog_or_tty->print_cr("GC Cause: %s", GCCause::to_string(gc_cause()));
        }
      }

  {- -------------------------------------------
  (1) (以下のブロック内では _is_gc_active を true にしておく)
      ---------------------------------------- -}

      {
        FlagSetting fl(_is_gc_active, true);

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

        bool complete = full && (max_level == (n_gens()-1));
        const char* gc_cause_str = "GC ";
        if (complete) {
          GCCause::Cause cause = gc_cause();
          if (cause == GCCause::_java_lang_system_gc) {
            gc_cause_str = "Full GC (System) ";
          } else {
            gc_cause_str = "Full GC ";
          }
        }

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

        gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
        TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
        TraceTime t(gc_cause_str, PrintGCDetails, false, gclog_or_tty);

  {- -------------------------------------------
  (1) GenCollectedHeap::gc_prologue() を呼び出して, GC の前準備を行う.
      ---------------------------------------- -}

        gc_prologue(complete);

  {- -------------------------------------------
  (1) GC を行うことになったので, CollectedHeap::total_collections() の値を増加させておく.
      (See: CollectedHeap::total_collections())
      ---------------------------------------- -}

        increment_total_collections(complete);

  {- -------------------------------------------
  (1) (変数宣言など)
      (starting_level は, 最初に GC を試みる世代を表す)
      ---------------------------------------- -}

        size_t gch_prev_used = used();

        int starting_level = 0;
        if (full) {
          // Search for the oldest generation which will collect all younger
          // generations, and start collection loop there.
          for (int i = max_level; i >= 0; i--) {
            if (_gens[i]->full_collects_younger_generations()) {
              starting_level = i;
              break;
            }
          }
        }

        bool must_restore_marks_for_biased_locking = false;

  {- -------------------------------------------
  (1) (以下の for ループ内で実際の GC 処理を行う. 
      GC は starting_level 変数が示す世代から開始し, 
      Generation::should_collect() が true を返す全ての Generation に対して行う)
      (なお, ループ処理中に確保要求が満たせる世代ができた場合は, 
      その時点で size 変数が 0 にセットされる(後述)ことに注意)
      ---------------------------------------- -}

        int max_level_collected = starting_level;
        for (int i = starting_level; i <= max_level; i++) {
          if (_gens[i]->should_collect(full, size, is_tlab)) {

    {- -------------------------------------------
  (1.1) もし Major GC を実行する場合は, CollectedHeap::pre_full_gc_dump() を呼び出しておく.
        (これは保守運用機能用の関数. 関連するコマンドラインオプションの値に応じてヒープの情報を出力する)

        また, インクリメントされていなければ total_full_collections をインクリメントしておく.
        ---------------------------------------- -}

            if (i == n_gens() - 1) {  // a major collection is to happen
              if (!complete) {
                // The full_collections increment was missed above.
                increment_total_full_collections();
              }
              pre_full_gc_dump();    // do any pre full gc dumps
            }

    {- -------------------------------------------
  (1.1) (トレース出力用の処理)
        ---------------------------------------- -}

            // Timer for individual generations. Last argument is false: no CR
            TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty);
            TraceCollectorStats tcs(_gens[i]->counters());

    {- -------------------------------------------
  (1.1) (トレース出力用の処理) (DTrace のフック点) (JMM のフック点)
        (See: TraceMemoryManagerStats)
        ---------------------------------------- -}

            TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause());

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

            size_t prev_used = _gens[i]->used();

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

            _gens[i]->stat_record()->invocations++;
            _gens[i]->stat_record()->accumulated_time.start();

    {- -------------------------------------------
  (1.1) (デバッグ用の処理)
        GenCollectedHeap::record_gen_tops_before_GC() を呼ぶ
        (この中では, ZapUnusedHeapArea オプションが指定されていれば, 
        各 Generation に対してこの時点での使用量を記録する)
        ---------------------------------------- -}

            // Must be done anew before each collection because
            // a previous collection will do mangling and will
            // change top of some spaces.
            record_gen_tops_before_GC();

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

            if (PrintGC && Verbose) {
              gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
                         i,
                         _gens[i]->stat_record()->invocations,
                         size*HeapWordSize);
            }

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

            if (VerifyBeforeGC && i >= VerifyGCLevel &&
                total_collections() >= VerifyGCStartAt) {
              HandleMark hm;  // Discard invalid handles created during verification
              if (!prepared_for_verification) {
                prepare_for_verify();
                prepared_for_verification = true;
              }
              gclog_or_tty->print(" VerifyBeforeGC:");
              Universe::verify(true);
            }

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

            COMPILER2_PRESENT(DerivedPointerTable::clear());

    {- -------------------------------------------
  (1.1) BiasedLocking::preserve_marks() を呼んで, 
        mark フィールドが biased pattern になっているオブジェクトのうち
        現在ロックを取得されているものについては, 
        その mark 値を待避しておく.
        (この後の GC 処理では, 生きているオブジェクトに (生きているということを示すための) 印を付ける.
         この印はオブジェクトの mark フィールドに書き込まれるが, 
         そのままだと元の mark フィールドの値は失われてしまうので, 
         元の mark をどこかに待避しておいて, GC 後に書き戻してやる必要がある.)

        (なお, 複数回行う必要は無いので, 
        must_restore_marks_for_biased_locking 変数に既に行ったかどうかを記録している.
        既に行っていた場合は呼び出さない)
        ---------------------------------------- -}

            if (!must_restore_marks_for_biased_locking &&
                _gens[i]->performs_in_place_marking()) {
              // We perform this mark word preservation work lazily
              // because it's only at this point that we know whether we
              // absolutely have to do it; we want to avoid doing it for
              // scavenge-only collections where it's unnecessary
              must_restore_marks_for_biased_locking = true;
              BiasedLocking::preserve_marks();
            }

    {- -------------------------------------------
  (1.1) (以下のブロック内で実際の GC 処理を行う)
        ---------------------------------------- -}

            // Do collection work
            {

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

              // Note on ref discovery: For what appear to be historical reasons,
              // GCH enables and disabled (by enqueing) refs discovery.
              // In the future this should be moved into the generation's
              // collect method so that ref discovery and enqueueing concerns
              // are local to a generation. The collect method could return
              // an appropriate indication in the case that notification on
              // the ref lock was needed. This will make the treatment of
              // weak refs more uniform (and indeed remove such concerns
              // from GCH). XXX

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

              HandleMark hm;  // Discard invalid handles created during gc

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

              save_marks();   // save marks for all gens

    {- -------------------------------------------
  (1.1) これから GC を行うので, ReferenceProcessor オブジェクトをリセットしておく.
        ---------------------------------------- -}

              // We want to discover references, but not process them yet.
              // This mode is disabled in process_discovered_references if the
              // generation does some collection work, or in
              // enqueue_discovered_references if the generation returns
              // without doing any work.
              ReferenceProcessor* rp = _gens[i]->ref_processor();
              // If the discovery of ("weak") refs in this generation is
              // atomic wrt other collectors in this configuration, we
              // are guaranteed to have empty discovered ref lists.
              if (rp->discovery_is_atomic()) {
                rp->verify_no_references_recorded();
                rp->enable_discovery();
                rp->setup_policy(do_clear_all_soft_refs);
              } else {
                // collect() below will enable discovery as appropriate
              }

    {- -------------------------------------------
  (1.1) Generation::collect() を呼んで GC を行う.
        (なお, Generation::collect() は Generation クラスの各サブクラスによってオーバーライドされているため, 
         処理は Generation 毎に異なる)
        ---------------------------------------- -}

              _gens[i]->collect(full, do_clear_all_soft_refs, size, is_tlab);

    {- -------------------------------------------
  (1.1) ReferenceProcessor::enqueue_discovered_references() で
        リストに残った参照オブジェクト(= 差し先が死んだため特殊な処理が必要な参照オブジェクト)を pending list に追加する.
        ---------------------------------------- -}

              if (!rp->enqueuing_is_done()) {
                rp->enqueue_discovered_references();
              } else {
                rp->set_enqueuing_is_done(false);
              }
              rp->verify_no_references_recorded();
            }

    {- -------------------------------------------
  (1.1) GC を実行した世代の番号を記録しておく
        ---------------------------------------- -}

            max_level_collected = i;

    {- -------------------------------------------
  (1.1) 現在の Generation で確保要求が満たせるようになった場合は, 
        size 変数を 0 にしてしまう.
        ---------------------------------------- -}

            // Determine if allocation request was met.
            if (size > 0) {
              if (!is_tlab || _gens[i]->supports_tlab_allocation()) {
                if (size*HeapWordSize <= _gens[i]->unsafe_max_alloc_nogc()) {
                  size = 0;
                }
              }
            }

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

            COMPILER2_PRESENT(DerivedPointerTable::update_pointers());

    {- -------------------------------------------
  (1.1) GC 終了時の時刻を記録しておく.
        ---------------------------------------- -}

            _gens[i]->stat_record()->accumulated_time.stop();

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

            update_gc_stats(i, full);

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

            if (VerifyAfterGC && i >= VerifyGCLevel &&
                total_collections() >= VerifyGCStartAt) {
              HandleMark hm;  // Discard invalid handles created during verification
              gclog_or_tty->print(" VerifyAfterGC:");
              Universe::verify(false);
            }

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

            if (PrintGCDetails) {
              gclog_or_tty->print(":");
              _gens[i]->print_heap_change(prev_used);
            }
          }
        }

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

        // Update "complete" boolean wrt what actually transpired --
        // for instance, a promotion failure could have led to
        // a whole heap collection.
        complete = complete || (max_level_collected == n_gens() - 1);

  {- -------------------------------------------
  (1) (保守運用機能用の処理)
      Major GC を実行した場合は, CollectedHeap::post_full_gc_dump() を呼び出す.
      (この中では関連するコマンドラインオプションの値に応じてヒープの情報を出力する)
      ---------------------------------------- -}

        if (complete) { // We did a "major" collection
          post_full_gc_dump();   // do any post full gc dumps
        }

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

        if (PrintGCDetails) {
          print_heap_change(gch_prev_used);

          // Print perm gen info for full GC with PrintGCDetails flag.
          if (complete) {
            print_perm_heap_change(perm_prev_used);
          }
        }

  {- -------------------------------------------
  (1) ゴミを回収した各領域に対して Generation::compute_new_size() を呼び出し, 
      領域の大きさを最適に調整しておく.
      ---------------------------------------- -}

        for (int j = max_level_collected; j >= 0; j -= 1) {
          // Adjust generation sizes.
          _gens[j]->compute_new_size();
        }

  {- -------------------------------------------
  (1) Perm 領域内のゴミも回収したので, 
       Generation::compute_new_size() を呼んで, 大きさを最適に調整しておく.
      ---------------------------------------- -}

        if (complete) {
          // Ask the permanent generation to adjust size for full collections
          perm()->compute_new_size();
          update_full_collections_completed();
        }

  {- -------------------------------------------
  (1) (プロファイル情報の記録)(JMM 用) (See: MemoryUsage)
      及び (JMM のフック点) でもある  (See: LowMemoryDetector)
      ---------------------------------------- -}

        // Track memory usage and detect low memory after GC finishes
        MemoryService::track_memory_usage();

  {- -------------------------------------------
  (1) GenCollectedHeap::gc_epilogue() を呼び出して, GC の後始末を行う
      ---------------------------------------- -}

        gc_epilogue(complete);

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

        if (must_restore_marks_for_biased_locking) {
          BiasedLocking::restore_marks();
        }
      }

  {- -------------------------------------------
  (1) (トラブルシューティング用の処理) (関連する manageable オプションが指定されている場合にのみ実行) (See: AdaptiveSizePolicyOutput)
      ---------------------------------------- -}

      AdaptiveSizePolicy* sp = gen_policy()->size_policy();
      AdaptiveSizePolicyOutput(sp, total_collections());

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

      if (PrintHeapAtGC) {
        Universe::print_heap_after_gc();
      }

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

    #ifdef TRACESPINNING
      ParallelTaskTerminator::print_termination_counts();
    #endif

  {- -------------------------------------------
  (1) (デバッグ用の処理)
      (ExitAfterGCNum オプションの処理.
       ExitAfterGCNum が指定されている場合, total_collections() が ExitAfterGCNum 回数まで達していれば, ここで HotSpot の実行を終了する)
      ---------------------------------------- -}

      if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) {
        tty->print_cr("Stopping after GC #%d", ExitAfterGCNum);
        vm_exit(-1);
      }
    }

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