Skip to content

g1 evacuation_Young

ceragon edited this page Dec 27, 2021 · 3 revisions

Only Young GC 的触发条件

Only Young GC 的调用代码

  1. 调用的方式为构造 VM_G1CollectForAllocation 类,且 gc_cause 一般为 _g1_inc_collection_pause
123
class VM_G1CollectForAllocation: public VM_CollectForAllocation {
    public:
  VM_G1CollectForAllocation(size_t         word_size,
                            uint           gc_count_before,
                            GCCause::Cause gc_cause,
                            bool           should_initiate_conc_mark,
                            double         target_pause_time_ms);
};
  1. 反查使用 _g1_inc_collection_pause 的使用,得到如下代码
HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
    if (should_try_gc) {
      bool succeeded;
      result = do_collection_pause(word_size, gc_count_before, &succeeded,
                                   GCCause::_g1_inc_collection_pause);
    }
}
  1. 而上面的 do_collection_pause 方法内容如下,由此可得 attempt_allocation_slow() 是造成 Young GC 的主要原因
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
                                               uint gc_count_before,
                                               bool* succeeded,
                                               GCCause::Cause gc_cause) {
    VM_G1CollectForAllocation op(word_size,
                               gc_count_before,
                               gc_cause,
                               false, /* should_initiate_conc_mark */
                               g1_policy()->max_pause_time_ms());
    VMThread::execute(&op);
}

attempt_allocation_slow() 调用链

  1. 该
inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size,
                                                     size_t desired_word_size,
                                                     size_t* actual_word_size) {
    // 普通分配的方法
    HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size);
    if (result == NULL) {
        *actual_word_size = desired_word_size;
        // 没有分配成功的时候,会尝试慢分配
        result = attempt_allocation_slow(desired_word_size);
    }
}
  1. 继续
HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size,
                                             size_t requested_size,
                                             size_t* actual_size) {
      return attempt_allocation(min_size, requested_size, actual_size);
}
HeapWord* G1CollectedHeap::mem_allocate(size_t word_size, bool*  gc_overhead_limit_was_exceeded) {
    size_t dummy = 0;
    return attempt_allocation(word_size, word_size, &dummy);
}

allocate_new_tlab()

HeapWord* MemAllocator::allocate_inside_tlab_slow(Allocation& allocation) const {
    mem = _heap->allocate_new_tlab(min_tlab_size, new_tlab_size, &allocation._allocated_tlab_size);
}

mem_allocate()

HeapWord* MemAllocator::allocate_outside_tlab(Allocation& allocation) const {
    HeapWord* mem = _heap->mem_allocate(_word_size, &allocation._overhead_limit_exceeded);
}

可以看到无论 inside 还是 outside 都是 TLAB 相关信息,详见 Thread Local Allocate Buffer

attempt_allocation_slow() 内容解析

HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
    ResourceMark rm; // For retrieving the thread names in log messages.
    HeapWord* result = NULL;
    for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
        bool should_try_gc;
        uint gc_count_before;
        {
          MutexLockerEx x(Heap_lock);
          result = _allocator->attempt_allocation_locked(word_size);
          if (result != NULL) {
            return result;
          }
          if (GCLocker::is_active_and_needs_gc() && g1_policy()->can_expand_young_list()) {
            result = _allocator->attempt_allocation_force(word_size);
            if (result != NULL) {
              return result;
            }
          }
          should_try_gc = !GCLocker::needs_gc();
          gc_count_before = total_collections();
        }
        if (should_try_gc) {
          bool succeeded;
          result = do_collection_pause(word_size, gc_count_before, &succeeded,
                                       GCCause::_g1_inc_collection_pause);
          // 省略代码
        }
        // 省略代码
   }
   return NULL;
}

attempt_allocation_locked()

  1. 方法内容如下
inline HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size) {
    HeapWord* result = mutator_alloc_region()->attempt_allocation_locked(word_size);
    return result;
}

attempt_allocation_locked()

  1. 代码
inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size) {
    return attempt_allocation_locked(word_size, word_size, &temp);
}
  1. 继续
inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t min_word_size,
                                                          size_t desired_word_size,
                                                          size_t* actual_word_size) {
    HeapWord* result = attempt_allocation(min_word_size, desired_word_size, actual_word_size);
    if (result != NULL) {
        return result;
    }
    retire(true /* fill_up */);
    result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
    if (result != NULL) {
        *actual_word_size = desired_word_size;
        return result;
    }
    return NULL;
}
attempt_allocation()
  1. 继续
inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
                                                   size_t desired_word_size,
                                                   size_t* actual_word_size) {
  HeapRegion* alloc_region = _alloc_region;
  HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size);
}
  1. 继续
inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region,
                                             size_t min_word_size,
                                             size_t desired_word_size,
                                             size_t* actual_word_size) {
    // 结合上下文,由于是被 attempt_allocation_locked 方法内的 mutator_alloc_region 调用,所以这里 _bot_updates 是 false
    if (!_bot_updates) {
        // 会进到这里
        return alloc_region->par_allocate_no_bot_updates(min_word_size, desired_word_size, actual_word_size);
    } else {
        return alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
    }
}
  1. 继续
inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t min_word_size,
                                                         size_t desired_word_size,
                                                         size_t* actual_word_size) {
    return par_allocate_impl(min_word_size, desired_word_size, actual_word_size);
}
  1. 继续
inline HeapWord* G1ContiguousSpace::par_allocate_impl(size_t min_word_size,
                                                      size_t desired_word_size,
                                                      size_t* actual_size) {
  do {
    HeapWord* obj = top();
    size_t available = pointer_delta(end(), obj);
    size_t want_to_allocate = MIN2(available, desired_word_size);
    if (want_to_allocate >= min_word_size) {
      HeapWord* new_top = obj + want_to_allocate;
      HeapWord* result = Atomic::cmpxchg(new_top, top_addr(), obj);
      if (result == obj) {
        *actual_size = want_to_allocate;
        return obj;
      }
    } else {
      return NULL;
    }
  } while (true);
}
new_alloc_region_and_allocate()
  1. 代码
HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, bool force) {
    HeapRegion* new_alloc_region = allocate_new_region(word_size, force);
    if (new_alloc_region != NULL) {
        new_alloc_region->reset_pre_dummy_top();
        _used_bytes_before = new_alloc_region->used();
        HeapWord* result = allocate(new_alloc_region, word_size);
        OrderAccess::storestore();
        update_alloc_region(new_alloc_region);
        return result;
    } 
}
allocate_new_region()
  1. allocate_new_region()
HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size, bool force) {
  return _g1h->new_mutator_alloc_region(word_size, force);
}
  1. new_mutator_alloc_region()
HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size,
                                                      bool force) {
  bool should_allocate = g1_policy()->should_allocate_mutator_region();
  if (force || should_allocate) {
    HeapRegion* new_alloc_region = new_region(word_size,
                                              false /* is_old */,
                                              false /* do_expand */);
    if (new_alloc_region != NULL) {
      set_region_short_lived_locked(new_alloc_region);
      _hr_printer.alloc(new_alloc_region, !should_allocate);
      _verifier->check_bitmaps("Mutator Region Allocation", new_alloc_region);
      _g1_policy->remset_tracker()->update_at_allocate(new_alloc_region);
      return new_alloc_region;
    }
  }
  return NULL;
}
  1. should_allocate_mutator_region()
bool G1Policy::should_allocate_mutator_region() const {
    // 当前的年轻代 region 个数
  uint young_list_length = _g1h->young_regions_count();
  // 年轻代的期望数量
  uint young_list_target_length = _young_list_target_length;
  // 没有超出期望值就为真
  return young_list_length < young_list_target_length;
}
  1. new_region()
HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_expand) {
    HeapRegion* res = _hrm.allocate_free_region(is_old);
    if (res == NULL && do_expand && _expand_heap_after_alloc_failure) {
        if (expand(word_size * HeapWordSize)) {
            res = _hrm.allocate_free_region(is_old);
        } else {
            _expand_heap_after_alloc_failure = false;
        }
    }
}

附录

Clone this wiki locally