Top


定義場所(file name)

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

名前(function name)

void CMTask::drain_region_stack(BitMapClosure* bc) {

本体部(body)

  {- -------------------------------------------
  (1) 何らかの理由でこの CMTask が中断されていたら, ここでリターン
      ---------------------------------------- -}

      if (has_aborted())
        return;

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

      assert(_region_finger == NULL,
             "it should be NULL when we're not scanning a region");

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

      if (!_cm->region_stack_empty() || !_aborted_region.is_empty()) {

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

        if (_cm->verbose_low())
          gclog_or_tty->print_cr("[%d] draining region stack, size = %d",
                                 _task_id, _cm->region_stack_size());

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

        MemRegion mr;

    {- -------------------------------------------
  (1.1) 次の処理対象を取得して mr 変数にセット.
        (_aborted_region があるならそれを使う (_aborted_region は空にもどしておく).
         そうでなければ, region_stack_pop_lock_free() で取得)
        (なお, _aborted_region は前回途中までしか処理できなかった領域があった場合にセットされている. この間数内の残りの処理参照.)
        ---------------------------------------- -}

        if (!_aborted_region.is_empty()) {
          mr = _aborted_region;
          _aborted_region = MemRegion();

          if (_cm->verbose_low())
            gclog_or_tty->print_cr("[%d] scanning aborted region [ " PTR_FORMAT ", " PTR_FORMAT " )",
                                 _task_id, mr.start(), mr.end());
        } else {
          mr = _cm->region_stack_pop_lock_free();
          // it returns MemRegion() if the pop fails
          statsOnly(if (mr.start() != NULL) ++_region_stack_pops );
        }

    {- -------------------------------------------
  (1.1) 以下, mr が空になるまでループ
        ---------------------------------------- -}

        while (mr.start() != NULL) {

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

          if (_cm->verbose_medium())
            gclog_or_tty->print_cr("[%d] we are scanning region "
                                   "["PTR_FORMAT", "PTR_FORMAT")",
                                   _task_id, mr.start(), mr.end());

      {- -------------------------------------------
  (1.1.1) (assert)
          ---------------------------------------- -}

          assert(mr.end() <= _cm->finger(),
                 "otherwise the region shouldn't be on the stack");
          assert(!mr.is_empty(), "Only non-empty regions live on the region stack");

      {- -------------------------------------------
  (1.1.1) BitMap::iterate() を呼んで, 対象の mr に対して bc 引数のクロージャを適用する.
          * 成功し, かつまだ abort してない場合
            region_stack_pop_lock_free() で次の処理対象を取得.
            (ついでに, デバッグ時(?)には _region_stack_pops もインクリメントしてるが)
          * 成功したが, abort された場合
            mr に MemRegion() をセットする (これによりループから抜ける)
          * 失敗した場合
            nextWord() で残りの処理対象を取得し, 空でなかった場合は _aborted_region にセットしておく (後で処理し直すため).
            その後 mr に MemRegion() をセットする (これによりループから抜ける)

          なお, どの場合も最後に _region_finger を NULL に戻してからループの次の週に進む.
          ---------------------------------------- -}

          if (_nextMarkBitMap->iterate(bc, mr)) {
            assert(!has_aborted(),
                   "cannot abort the task without aborting the bitmap iteration");

            // We finished iterating over the region without aborting.
            regular_clock_call();
            if (has_aborted())
              mr = MemRegion();
            else {
              mr = _cm->region_stack_pop_lock_free();
              // it returns MemRegion() if the pop fails
              statsOnly(if (mr.start() != NULL) ++_region_stack_pops );
            }
          } else {
            assert(has_aborted(), "currently the only way to do so");

            // The only way to abort the bitmap iteration is to return
            // false from the do_bit() method. However, inside the
            // do_bit() method we move the _region_finger to point to the
            // object currently being looked at. So, if we bail out, we
            // have definitely set _region_finger to something non-null.
            assert(_region_finger != NULL, "invariant");

            // Make sure that any previously aborted region has been
            // cleared.
            assert(_aborted_region.is_empty(), "aborted region not cleared");

            // The iteration was actually aborted. So now _region_finger
            // points to the address of the object we last scanned. If we
            // leave it there, when we restart this task, we will rescan
            // the object. It is easy to avoid this. We move the finger by
            // enough to point to the next possible object header (the
            // bitmap knows by how much we need to move it as it knows its
            // granularity).
            MemRegion newRegion =
              MemRegion(_nextMarkBitMap->nextWord(_region_finger), mr.end());

            if (!newRegion.is_empty()) {
              if (_cm->verbose_low()) {
                gclog_or_tty->print_cr("[%d] recording unscanned region"
                                       "[" PTR_FORMAT "," PTR_FORMAT ") in CMTask",
                                       _task_id,
                                       newRegion.start(), newRegion.end());
              }
              // Now record the part of the region we didn't scan to
              // make sure this task scans it later.
              _aborted_region = newRegion;
            }
            // break from while
            mr = MemRegion();
          }
          _region_finger = NULL;
        }

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

        if (_cm->verbose_low())
          gclog_or_tty->print_cr("[%d] drained region stack, size = %d",
                                 _task_id, _cm->region_stack_size());
      }
    }

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