Hotspot 垃圾回收之CMSCollector(五) 源码解析

   目录

1、CMSParRemarkTask

2、Par_MarkRefsIntoAndScanClosure

3、Par_PushAndMarkClosure

4、RemarkKlassClosure

5、MarkFromDirtyCardsClosure

6、ScanMarkedObjectsAgainClosure

7、FinalMarking 步骤总结

8、sweep

 9、SweepClosure

 9.1、do_blk_careful

9.2、do_already_free_chunk 

9.3 、do_garbage_chunk

9.4、do_live_chunk

10、Sweeping步骤 总结


本篇继续上一篇《Hotspot 垃圾回收之CMSCollector(四) 源码解析》讲解FinalMarking和Sweeping步骤的相关实现。

1、CMSParRemarkTask

     CMSParRemarkTask用于并行的执行再次标记,是do_remark_parallel方法的核心,其实现如下:

CMSParRemarkTask(CMSCollector* collector,
                   CompactibleFreeListSpace* cms_space,
                   int n_workers, FlexibleWorkGang* workers,
                   OopTaskQueueSet* task_queues):
    CMSParMarkTask("Rescan roots and grey objects in parallel",
                   collector, n_workers),
    _cms_space(cms_space),
    _task_queues(task_queues),
    _term(n_workers, task_queues) { }

void CMSParRemarkTask::work(uint worker_id) {
  elapsedTimer _timer;
  ResourceMark rm;
  HandleMark   hm;

  // ---------- rescan from roots --------------
  _timer.start();
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  Par_MarkRefsIntoAndScanClosure par_mrias_cl(_collector,
    _collector->_span, _collector->ref_processor(),
    &(_collector->_markBitMap),
    work_queue(worker_id));

  //遍历年轻代的对象
  {
    work_on_young_gen_roots(worker_id, &par_mrias_cl);
    _timer.stop();
    if (PrintCMSStatistics != 0) {
      gclog_or_tty->print_cr(
        "Finished young gen rescan work in %dth thread: %3.3f sec",
        worker_id, _timer.seconds());
    }
  }

  // ---------- remaining roots --------------
  _timer.reset();
  _timer.start();
  //遍历Universe,SystemDictionary,StringTable等类中包含的oop
  gch->gen_process_roots(_collector->_cmsGen->level(),
                         false,     // yg was scanned above
                         false,     // this is parallel code
                         GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
                         _collector->should_unload_classes(),
                         &par_mrias_cl,
                         NULL,
                         NULL);     // The dirty klasses will be handled below

  assert(_collector->should_unload_classes()
         || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
         "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
  _timer.stop();
  if (PrintCMSStatistics != 0) {
    gclog_or_tty->print_cr(
      "Finished remaining root rescan work in %dth thread: %3.3f sec",
      worker_id, _timer.seconds());
  }

  // ---------- unhandled CLD scanning ----------
  if (worker_id == 0) { //只需要worker_id等于0的这一个线程处理即可
    _timer.reset();
    _timer.start();

    //遍历新增的ClassLoaderData
    ResourceMark rm;
    GrowableArray<ClassLoaderData*>* array = ClassLoaderDataGraph::new_clds();
    for (int i = 0; i < array->length(); i++) {
      par_mrias_cl.do_class_loader_data(array->at(i));
    }

    ClassLoaderDataGraph::remember_new_clds(false);

    _timer.stop();
    if (PrintCMSStatistics != 0) {
      gclog_or_tty->print_cr(
          "Finished unhandled CLD scanning work in %dth thread: %3.3f sec",
          worker_id, _timer.seconds());
    }
  }

  // ---------- dirty klass scanning ----------
  if (worker_id == 0) { //只需要worker_id等于0的这一个线程处理即可
    _timer.reset();
    _timer.start();

    //遍历所有的ClassLoaderData
    RemarkKlassClosure remark_klass_closure(&par_mrias_cl);
    ClassLoaderDataGraph::classes_do(&remark_klass_closure);

    _timer.stop();
    if (PrintCMSStatistics != 0) {
      gclog_or_tty->print_cr(
          "Finished dirty klass scanning work in %dth thread: %3.3f sec",
          worker_id, _timer.seconds());
    }
  }


  // ---------- rescan dirty cards ------------
  _timer.reset();
  _timer.start();

  //遍历脏的卡表
  do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl);
  _timer.stop();
  if (PrintCMSStatistics != 0) {
    gclog_or_tty->print_cr(
      "Finished dirty card rescan work in %dth thread: %3.3f sec",
      worker_id, _timer.seconds());
  }

  // ---------- steal work from other threads ...
  // ---------- ... and drain overflow list.
  _timer.reset();
  _timer.start();
  do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id));
  _timer.stop();
  if (PrintCMSStatistics != 0) {
    gclog_or_tty->print_cr(
      "Finished work stealing in %dth thread: %3.3f sec",
      worker_id, _timer.seconds());
  }
}

void
CMSParRemarkTask::do_dirty_card_rescan_tasks(
  CompactibleFreeListSpace* sp, int i,
  Par_MarkRefsIntoAndScanClosure* cl) {

  ResourceMark rm;
  HandleMark   hm;

  OopTaskQueue* work_q = work_queue(i);
  ModUnionClosure modUnionClosure(&(_collector->_modUnionTable));
  
  //full_span对应完整的老年代空间
  MemRegion  full_span  = _collector->_span;
  CMSBitMap* bm    = &(_collector->_markBitMap);     // shared
  MarkFromDirtyCardsClosure
    greyRescanClosure(_collector, full_span, // entire span of interest
                      sp, bm, work_q, cl);

  SequentialSubTasksDone* pst = sp->conc_par_seq_tasks();
  assert(pst->valid(), "Uninitialized use?");
  uint nth_task = 0;
  const int alignment = CardTableModRefBS::card_size * BitsPerWord;
  MemRegion span = sp->used_region();
  HeapWord* start_addr = span.start();
  HeapWord* end_addr = (HeapWord*)round_to((intptr_t)span.end(),
                                           alignment);
  const size_t chunk_size = sp->rescan_task_size(); // in HeapWord units
  assert((HeapWord*)round_to((intptr_t)start_addr, alignment) ==
         start_addr, "Check alignment");
  assert((size_t)round_to((intptr_t)chunk_size, alignment) ==
         chunk_size, "Check alignment");

  //is_task_claimed方法会原子的改变nth_task的值
  while (!pst->is_task_claimed(/* reference */ nth_task)) {
    //计算遍历的内存区域
    MemRegion this_span = MemRegion(start_addr + nth_task*chunk_size,
                                    start_addr + (nth_task+1)*chunk_size);
    if (this_span.end() > end_addr) {
      //不能超过end_addr
      this_span.set_end(end_addr);
      assert(!this_span.is_empty(), "Program logic (calculation of n_tasks)");
    }
    //不断遍历,找到一段连续的脏的卡表项,将其对应的内存区域在modUnionTable中打标,
    _collector->_ct->ct_bs()->dirty_card_iterate(this_span,
                                                 &modUnionClosure);

    //不断遍历,找到一段连续的被打标的位,使用greyRescanClosure来遍历对应的内存区域中的对象
    _collector->_modUnionTable.dirty_range_iterate_clear(
                  this_span, &greyRescanClosure);
    _collector->_modUnionTable.verifyNoOneBitsInRange(
                                 this_span.start(),
                                 this_span.end());
  }
  pst->all_tasks_completed();  //标记线程执行结束
}

void
CMSParRemarkTask::do_work_steal(int i, Par_MarkRefsIntoAndScanClosure* cl,
                                int* seed) {
  OopTaskQueue* work_q = work_queue(i);
  NOT_PRODUCT(int num_steals = 0;)
  oop obj_to_scan;
  CMSBitMap* bm = &(_collector->_markBitMap);

  while (true) {
    //遍历work_queue中的oop
    cl->trim_queue(0);
    //ParGCDesiredObjsFromOverflowList的默认值是20,计算从overflow_list中取出待处理oop的个数
    size_t num_from_overflow_list = MIN2((size_t)(work_q->max_elems() - work_q->size())/4,
                                         (size_t)ParGCDesiredObjsFromOverflowList);
    //从overflow_list中最多哦取出num_from_overflow_list个放入work_q
    if (_collector->par_take_from_overflow_list(num_from_overflow_list,
                                                work_q,
                                                ParallelGCThreads)) {
      //取出成功,不需要从其他线程的work_queue中偷待处理的oop
      continue;
    }
    assert(work_q->size() == 0, "Have work, shouldn't steal");
    //尝试从其他work_queue中偷一个待处理的oop
    if (task_queues()->steal(i, seed, /* reference */ obj_to_scan)) {
      assert(obj_to_scan->is_oop(), "Oops, not an oop!");
      assert(bm->isMarked((HeapWord*)obj_to_scan), "Stole an unmarked oop?");
      //遍历该oop所引用的其他oop
      obj_to_scan->oop_iterate(cl);
    } else if (terminator()->offer_termination()) {
     //没有偷到,其他线程的work_queue也是空的,尝试几次后则终止循环
        break; 
    }
  }

  assert(work_q->size() == 0 && _collector->overflow_list_is_empty(),
         "Else our work is not yet done");
}

bool CMSCollector::par_take_from_overflow_list(size_t num,
                                               OopTaskQueue* work_q,
                                               int no_of_gc_threads) {
  //校验work_q是空的
  assert(work_q->size() == 0, "First empty local work queue");
  assert(num < work_q->max_elems(), "Can't bite more than we can chew");
  if (_overflow_list == NULL) {
    //_overflow_list是空的
    return false;
  }
  //BUSY是一个特殊的实际并不存在的一个地址
  oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
  Thread* tid = Thread::current();
  size_t CMSOverflowSpinCount = (size_t) no_of_gc_threads; // was ParallelGCThreads;
  size_t sleep_time_millis = MAX2((size_t)1, num/100);
  // If the list is busy, we spin for a short while,
  // sleeping between attempts to get the list.
  for (size_t spin = 0; prefix == BUSY && spin < CMSOverflowSpinCount; spin++) {
    os::sleep(tid, sleep_time_millis, false);
    if (_overflow_list == NULL) {
      //为空,表示_overflow_list已经空了
      return false;
    } else if (_overflow_list != BUSY) {
      //不等于BUSY说明里面有待处理的oop,则尝试抢占,如果抢占成功,prefix就是之前的_overflow_list
      //然后_overflow_list变成BUSY,等待Closure往里面放待处理的oop
      prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
    }
  }
  //遍历结束,要么达到CMSOverflowSpinCount次数限制,要么prefix是非BUSY
  if (prefix == NULL || prefix == BUSY) {
     //达到次数限制了
     if (prefix == NULL) {
       //将_overflow_list由BUSY置为NULL
       (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
     }
     return false;
  }
  assert(prefix != NULL && prefix != BUSY, "Error");
  size_t i = num;
  //因为_overflow_list是通过对象头指针构成的链表,所以拿到了_overflow_list就意味着拿到了整个链表
  oop cur = prefix;
  //往后遍历,找到最后一个需要取出的oop
  for (; i > 1 && cur->mark() != NULL; cur = oop(cur->mark()), i--);
  if (cur->mark() == NULL) {
    //_overflow_list被全部取完了
    if (_overflow_list == BUSY) {
      //将_overflow_list由BUSY置为NULL
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值