栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

panda白话 - G1垃圾收集器 - Mixed GC - 并发标记阶段 - 源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

panda白话 - G1垃圾收集器 - Mixed GC - 并发标记阶段 - 源码分析

G1垃圾收集 - Mixed GC:

  • 初始标记阶段 - Initial Mark
  • 并发标记阶段 - Concurrent Mark
  • 最终标记阶段 - Remark
  • 清理阶段 - Clean Up

并发标记阶段 - Concurrent Mark

特性:

  • 并发 - 与Mutator并发进行
  • 并发阶段Mutator产生的新的引用或引用的更新,会被SATB的写屏障记录下来
  • 以初始标记的根出发进行深度扫描
  • 标记过程可以被Young GC打断

并发标记步骤:

  • markFromRoots从根开始扫描标记
  • 创建并发标记任务类 CMConcurrentMarkingTask
  • 循环执行标记任务do_marking_step
  • 处理satb缓冲区drain_satb_buffers、处理本地队列drain_local_queue、处理全局栈drain_global_stack
  • process_grey_object根据nextMarkBitMap中标记的对象,针对每个对象的field递归并发标记、即染灰

结果: 标记出整个堆的存活对象,统计存活数量


源码分析:

并发标记源码在:concurrentMark.cpp

void ConcurrentMark::markFromRoots() {
   //重置溢出启动标记标志
  _restart_for_overflow = false;
  force_overflow_conc()->init();
  
  //获取并行标记线程
  _parallel_marking_threads = calc_parallel_marking_threads();
  uint active_workers = MAX2(1U, parallel_marking_threads());
  
  //设置并行任务结束符
  set_concurrency_and_phase(active_workers, true );
  
  //创建任务类CMConcurrentMarkingTask  执行并发标记
  CMConcurrentMarkingTask markingTask(this, cmThread());
  
  //根据并行策略执行
  if (use_parallel_marking_threads()) {
    _parallel_workers->set_active_workers((int)active_workers);
    _parallel_workers->run_task(&markingTask);
  } else {
    markingTask.work(0);
  }
  print_stats();
}

我们继续追CMConcurrentMarkingTask 的work方法:

  • 处理SATB 缓存
  • 根据已经标记的分区nextBitMap位图对象进行处理,针对每个已标记对象的每个field进行递归并发标记
public:void work(uint worker_id) {
    ResourceMark rm;
    //当发生同步时,进行等待
    SuspendibleThreadSet::join();
    
    //根据work_id 读取并发标记任务
    CMTask* the_task = _cm->task(worker_id);
    if (!_cm->has_aborted()) {
      do { 
        // 可以通过参数设置并发标记目标时间,默认值10ms,标识并发标记在10ms内完成
        double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
        //开始执行并发标记
        the_task->do_marking_step(mark_step_duration_ms,//超时时间
                                  true  ,
                                  false );
       ......                           
        //清理溢出标记
        _cm->clear_has_overflown();
        _cm->do_yield_check(worker_id);
        ......
       //循环结束条件 : 1、并发标记终止 2、并发标记任务终止
      } while (!_cm->has_aborted() && the_task->has_aborted());
    }
  }
};

我们继续追 do_marking_step 方法:

//执行标记任务
void CMTask::do_marking_step(double time_target_ms,//标记时间
                             bool do_termination,
                             bool is_serial) {

  //G1 回收策略
  G1CollectorPolicy* g1_policy = _g1h->g1_policy();
  _claimed = true;

  //是否偷其他线程任务处理的标志
  bool do_stealing = do_termination && !is_serial;
  //获取标记目标时间
  double diff_prediction_ms = g1_policy->get_new_prediction(&_marking_step_diffs_ms);
  _time_target_ms = time_target_ms - diff_prediction_ms;

  _words_scanned = 0;
  _refs_reached  = 0;
  recalculate_limits();

  // 清除并发任务终止的flag 和其他flag
  clear_has_aborted();
  _has_timed_out = false;
  _draining_satb_buffers = false;
  ++_calls;

  //闭包 后面用
  CMBitMapClosure bitmap_closure(this, _cm, _nextMarkBitMap);
  G1CMOopClosure  cm_oop_closure(_g1h, _cm, this);
  set_cm_oop_closure(&cm_oop_closure);

  //溢出、则任务终止
  if (_cm->has_overflown()) {
    set_has_aborted();
  }
    //处理satb缓冲区
  drain_satb_buffers();
    //处理本地队列
  drain_local_queue(true);
    //处理全局栈
  drain_global_stack(true);

  do {
    if (!has_aborted() && _curr_region != NULL) {
      update_region_limit();
      //MemRegion是新增的对象,从finger开始到结束全部开始标记
      MemRegion mr = MemRegion(_finger, _region_limit);

      //region为空,放弃处理
      if (mr.is_empty()) {
        giveup_current_region();
        regular_clock_call();
      //如果是大对象 并且 是该对象的最后一个分区
      } else if (_curr_region->isHumongous() && mr.start() == _curr_region->bottom()) {
      	//如果对象已经被标记 ,对象需置灰处理
        if (_nextMarkBitMap->isMarked(mr.start())) {
          BitMap::idx_t offset = _nextMarkBitMap->heapWordToOffset(mr.start());
          //处理对象的field指向的对象,形成递归
          bitmap_closure.do_bit(offset);
        }
        //如果对象未被标记、直接结束本分区
        giveup_current_region();
        regular_clock_call();
      //处理本分区标记对象,递归
      } else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) {
        giveup_current_region();
        regular_clock_call();
      } else {
        HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger);
        if (new_finger >= _region_limit) {
          giveup_current_region();
        } else {
          move_finger_to(new_finger);
        }
      }
    }

    //处理本地队列
    drain_local_queue(true);
    //处理全局栈
    drain_global_stack(true);

    while (!has_aborted() && _curr_region == NULL && !_cm->out_of_regions()) {
      //获取一个region
      HeapRegion* claimed_region = _cm->claim_region(_worker_id);
      if (claimed_region != NULL) {
        statsOnly( ++_regions_claimed );
        //将新的region加载到标记任务
        setup_for_region(claimed_region);
      }
      regular_clock_call();
    }
    //region为空或处理完
  } while ( _curr_region != NULL && !has_aborted());

  if (!has_aborted()) {
    //处理satb缓冲区
    drain_satb_buffers();
  }

  //处理本地队列
  drain_local_queue(false);
  //处理全局栈
  drain_global_stack(false);

  if (do_stealing && !has_aborted()) {
    while (!has_aborted()) {
      oop obj;
      statsOnly( ++_steal_attempts );
      if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
        statsOnly( ++_steals );
        scan_object(obj);
        drain_local_queue(false);
        drain_global_stack(false);
      } else {
        break;
      }
    }
  }
  if (do_termination && !has_aborted()) {
    if (_cm->force_overflow()->should_force()) {
      _cm->set_has_overflown();
      regular_clock_call();
    }
  }

    //执行中止操作
  if (do_termination && !has_aborted()) {
    _termination_start_time_ms = os::elapsedVTime() * 1000.0;
    bool finished = (is_serial || _cm->terminator()->offer_termination(this));
    double termination_end_time_ms = os::elapsedVTime() * 1000.0;
    _termination_time_ms += termination_end_time_ms - _termination_start_time_ms;
    //中止成功
    if (finished) {
      if (_worker_id == 0) {
        if (concurrent()) {
          _cm->clear_concurrent_marking_in_progress();
        }
      }
    } else {//中止失败
      set_has_aborted();
      statsOnly( ++_aborted_termination );
    }
  }

  //清除闭包
  set_cm_oop_closure(NULL);
  double end_time_ms = os::elapsedVTime() * 1000.0;
  double elapsed_time_ms = end_time_ms - _start_time_ms;
  _step_times_ms.add(elapsed_time_ms);

  //收尾工作
  if (has_aborted()) {
    statsOnly( ++_aborted );
    //判断是否超时
    if (_has_timed_out) {
      double diff_ms = elapsed_time_ms - _time_target_ms;
      _marking_step_diffs_ms.add(diff_ms);
    }
    //判断全局栈是否溢出
    if (_cm->has_overflown()) {
      if (!is_serial) {
        _cm->enter_first_sync_barrier(_worker_id);
      }

      statsOnly( ++_aborted_overflow );
      clear_region_fields();

      if (!is_serial) {
        _cm->enter_second_sync_barrier(_worker_id);
      }
    }
  }
  _claimed = false;
}

继续追处理satb方法drain_satb_buffers,最终会调用 deal_with_reference:

//处理对象引用
inline void CMTask::deal_with_reference(oop obj) {
  increment_refs_reached();
  HeapWord* objAddr = (HeapWord*) obj;
  if (_g1h->is_in_g1_reserved(objAddr)) {
    //判断是否被NTAMS标记
    if (!_nextMarkBitMap->isMarked(objAddr)) {
      HeapRegion* hr = _g1h->heap_region_containing_raw(obj);
      if (!hr->obj_allocated_since_next_marking(obj)) {
        make_reference_grey(obj, hr);
      }
    }
  }
}

主要工作在 make_reference_grey

inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
    //对对象进行标记和计数
  if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
    HeapWord* global_finger = _cm->finger();
    if (is_below_finger(obj, global_finger)) {
       if (obj->is_typeArray()) {
        //对对象标记的同时处理每个字段、对每个field进行标记处理
        process_grey_object(obj);
      } else {
        push(obj);
      }
    }
  }
}

真真真真真真。。。不错的文章 ->>>>>>>>>>>>>>G1并发标记过程观点不错的文章

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/667158.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号