Top


定義場所(file name)

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

名前(function name)

oop G1ParCopyHelper::copy_to_survivor_space(oop old) {

本体部(body)

  {- -------------------------------------------
  (1) (変数宣言など)
      (なお, young_index を +1 としているのは... #TODO)
      ---------------------------------------- -}

      size_t    word_sz = old->size();
      HeapRegion* from_region = _g1->heap_region_containing_raw(old);
      // +1 to make the -1 indexes valid...
      int       young_index = from_region->young_index_in_cset()+1;
      assert( (from_region->is_young() && young_index > 0) ||
              (!from_region->is_young() && young_index == 0), "invariant" );
      G1CollectorPolicy* g1p = _g1->g1_policy();
      markOop m = old->mark();
      int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age()
                                               : m->age();

  {- -------------------------------------------
  (1) G1CollectorPolicy::evacuation_destination() を呼び出して, コピー先を表す GCAllocPurpose を計算する
      (昇格するのであれば GCAllocForSurvived, そうでなければ GCAllocForTenured になる.
       See: G1CollectorPolicy::evacuation_destination())
      ---------------------------------------- -}

      GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age,
                                                                 word_sz);

  {- -------------------------------------------
  (1) G1ParScanThreadState::allocate() で, コピー先の領域を確保する.
      ---------------------------------------- -}

      HeapWord* obj_ptr = _par_scan_state->allocate(alloc_purpose, word_sz);
      oop       obj     = oop(obj_ptr);

  {- -------------------------------------------
  (1) もしコピー先の領域の確保に失敗していたら, 
      G1CollectedHeap::handle_evacuation_failure_par() を呼んで後始末を行う.
      (失敗したオブジェクトに自分自身を指す forwarding pointer が埋められる)
      ---------------------------------------- -}

      if (obj_ptr == NULL) {
        // This will either forward-to-self, or detect that someone else has
        // installed a forwarding pointer.
        OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
        return _g1->handle_evacuation_failure_par(cl, old);
      }

  {- -------------------------------------------
  (1) (この先は Copy 処理が続く限りは連続的にメモリ領域を確保していくことになるので) 速度向上のためにプリフェッチしておく.
      ---------------------------------------- -}

      // We're going to allocate linearly, so might as well prefetch ahead.
      Prefetch::write(obj_ptr, PrefetchCopyIntervalInBytes);

  {- -------------------------------------------
  (1) oopDesc::forward_to_atomic() で, 対象の oop に確保した領域へのポインタ(forwarding ポインタ)を埋め込む.
      (NULL が返されれば成功で, このオブジェクトをコピーする責任は自分にあることになる.
       逆に NULL 以外が返ってきた場合は, 他のスレッドが既に forwarding pointer を埋め込み済みなので, コピー処理は行わない.)
      ---------------------------------------- -}

      oop forward_ptr = old->forward_to_atomic(obj);

  {- -------------------------------------------
  (1) もし oopDesc::forward_to_atomic() の結果が NULL であれば (= forwarding pointer の埋め込みに成功していれば), 
      以下の if ブロックの中でコピー処理を行う.
      ---------------------------------------- -}

      if (forward_ptr == NULL) {

    {- -------------------------------------------
  (1.1) オブジェクトの中身をコピー先の領域にコピーする.
        ---------------------------------------- -}

        Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz);

    {- -------------------------------------------
  (1.1) コピー先の mark フィールドを設定する.
        (なお, age を増やす処理は簡単に obj->incr_age()  だけでもいいのだが, 
         パフォーマンスのために少し場合分けして不要な処理を行わないようにしている, とのこと.)
        ---------------------------------------- -}

        if (g1p->track_object_age(alloc_purpose)) {
          // We could simply do obj->incr_age(). However, this causes a
          // performance issue. obj->incr_age() will first check whether
          // the object has a displaced mark by checking its mark word;
          // getting the mark word from the new location of the object
          // stalls. So, given that we already have the mark word and we
          // are about to install it anyway, it's better to increase the
          // age on the mark word, when the object does not have a
          // displaced mark word. We're not expecting many objects to have
          // a displaced marked word, so that case is not optimized
          // further (it could be...) and we simply call obj->incr_age().

          if (m->has_displaced_mark_helper()) {
            // in this case, we have to install the mark word first,
            // otherwise obj looks to be forwarded (the old mark word,
            // which contains the forward pointer, was copied)
            obj->set_mark(m);
            obj->incr_age();
          } else {
            m = m->incr_age();
            obj->set_mark(m);
          }
          _par_scan_state->age_table()->add(obj, word_sz);
        } else {
          obj->set_mark(m);
        }

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

        // preserve "next" mark bit
        if (_g1->mark_in_progress() && !_g1->is_obj_ill(old)) {
          if (!use_local_bitmaps ||
              !_par_scan_state->alloc_buffer(alloc_purpose)->mark(obj_ptr)) {
            // if we couldn't mark it on the local bitmap (this happens when
            // the object was not allocated in the GCLab), we have to bite
            // the bullet and do the standard parallel mark
            _cm->markAndGrayObjectIfNecessary(obj);
          }
    #if 1
          if (_g1->isMarkedNext(old)) {
            _cm->nextMarkBitMap()->parClear((HeapWord*)old);
          }
    #endif
        }

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

        size_t* surv_young_words = _par_scan_state->surviving_young_words();
        surv_young_words[young_index] += word_sz;

    {- -------------------------------------------
  (1.1) _scanner フィールドの G1ParScanClosure オブジェクトを引数として
        oopDesc::oop_iterate_backwards() を呼び出し, 
        処理対象のオブジェクト内にあるポインタを (_scanner オブジェクト内にある) G1ParScanThreadState オブジェクトに収集する.

        ただし, もし処理対象がポインタの配列で, かつ長さが 
        ParGCArrayScanChunk オプションの値よりも長いようであれば, 全部処理すると時間がかかりそうなのでここでは処理しない.
        代わりに, その配列には set_partial_array_mask() 関数で処理を pending にしたという印を付け, 
        未処理の配列自体を G1ParScanThreadState オブジェクト内に入れておく.
        (See: G1ParScanPartialArrayClosure)
        ---------------------------------------- -}

        if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) {
          arrayOop(old)->set_length(0);
          oop* old_p = set_partial_array_mask(old);
          _par_scan_state->push_on_queue(old_p);
        } else {
          // No point in using the slower heap_region_containing() method,
          // given that we know obj is in the heap.
          _scanner->set_region(_g1->heap_region_containing_raw(obj));
          obj->oop_iterate_backwards(_scanner);
        }

  {- -------------------------------------------
  (1) もし oopDesc::forward_to_atomic() の結果が NULL でなければ (= forwarding pointer の埋め込みに失敗したら), 
      自分はコピー処理はしなくてもよいので, 
      コピー先として確保したメモリ領域を G1ParScanThreadState::undo_allocation() で開放しておく.

      (この場合, 他スレッドが埋め込んだ forwarding pointer をリターンすることになる)
      ---------------------------------------- -}

      } else {
        _par_scan_state->undo_allocation(alloc_purpose, obj_ptr, word_sz);
        obj = forward_ptr;
      }

  {- -------------------------------------------
  (1) forwarding pointer をリターン.
      ---------------------------------------- -}

      return obj;
    }

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