JVM G1 源码分析(六)- 混合式GC

1. 简介

YGC整个过程都在STW下进行,出于减少停顿时间的考量,对于老年代的回收显然需要与Mutator同时进行,G1引入了混合式GC,与CMS算法类似,均采用了并发标记。

混合式回收主要分为如下子阶段:

  • 初始标记子阶段
  • 并发标记子阶段
  • 再标记子阶段
  • 清理子阶段
  • 垃圾回收

2. 算法概览

2.1 标记算法概览

由于混合式GC使用的是并发标记,Mutator可能会随时改变对象引用关系,从而导致漏标和错标。
错标仅导致浮动垃圾,并不会导致运行错误。而漏标会导致对象被错误的回收,进而产生严重错误;为了避免漏标,G1引入了三色标记法。

  • 白色:垃圾收集器未探测到的对象
  • 灰色:活着的对象,但是依然没有被垃圾收集器扫描过
  • 黑色:活着的对象,并且已经被垃圾收集器扫描过

2.2 STAB机制简介

SATB(start at the beginning),在并发标记时,如果对象引用关系发生变化,G1会通过putfield字节码中的写屏障将这一引用关系的变化写入G1SATBMarkQueueSet和G1SATBMarkQueue中。并在并发标记子阶段和再标记子阶段处理G1SATBMarkQueueSet和G1SATBMarkQueue中的数据。

3. 源码分析

3.1 是否进入并发标记判定

g1Policy.cpp

G1IHOPControl* G1Policy::create_ihop_control(const G1Predictions* predictor){
  if (G1UseAdaptiveIHOP) {
    return new G1AdaptiveIHOPControl(InitiatingHeapOccupancyPercent,
                                     predictor,
                                     G1ReservePercent,
                                     G1HeapWastePercent);
  } else {
    return new G1StaticIHOPControl(InitiatingHeapOccupancyPercent);
  }
}

bool G1Policy::need_to_start_conc_mark(const char* source, size_t alloc_word_size) {
  if (about_to_start_mixed_phase()) {
    return false;
  }

  size_t marking_initiating_used_threshold = _ihop_control->get_conc_mark_start_threshold();

  size_t cur_used_bytes = _g1h->non_young_capacity_bytes();
  size_t alloc_byte_size = alloc_word_size * HeapWordSize;
  size_t marking_request_bytes = cur_used_bytes + alloc_byte_size;

  bool result = false;
  if (marking_request_bytes > marking_initiating_used_threshold) {
    result = collector_state()->in_young_only_phase() && !collector_state()->in_young_gc_before_mixed();
    log_debug(gc, ergo, ihop)("%s occupancy: " SIZE_FORMAT "B allocation request: " SIZE_FORMAT "B threshold: " SIZE_FORMAT "B (%1.2f) source: %s",
                              result ? "Request concurrent cycle initiation (occupancy higher than threshold)" : "Do not request concurrent cycle initiation (still doing mixed collections)",
                              cur_used_bytes, alloc_byte_size, marking_initiating_used_threshold, (double) marking_initiating_used_threshold / _g1h->capacity() * 100, source);
  }

  return result;
}

void G1Policy::record_new_heap_size(uint new_number_of_regions) {
  // re-calculate the necessary reserve
  double reserve_regions_d = (double) new_number_of_regions * _reserve_factor;
  // We use ceiling so that if reserve_regions_d is > 0.0 (but
  // smaller than 1.0) we'll get 1.
  _reserve_regions = (uint) ceil(reserve_regions_d);

  _young_gen_sizer->heap_size_changed(new_number_of_regions);

  _ihop_control->update_target_occupancy(new_number_of_regions * HeapRegion::GrainBytes);
}

g1Policy.hpp

  size_t get_conc_mark_start_threshold() {
    guarantee(_target_occupancy > 0, "Target occupancy must have been initialized.");
    return (size_t) (_initial_ihop_percent * _target_occupancy / 100.0);
  }
  • YGC最后阶段判断是否启动并发标记
  • 判断的依据是分配和即将分配的内存占比是否大于阈值
  • 阈值受JVM参数InitiatingHeapOccupancyPercent控制,默认45

如果需要进行并发标记,则通知并发标记线程
g1CollectedHeap.cpp

void G1CollectedHeap::do_concurrent_mark() {
  Mut
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值