jvm(13) full gc 源碼 jdk17

full gc是g1正常的gc cycle回收無力的情況下進行的,相對來說比較簡單
主要入口代碼在 g1CollectedHeap.cpp
do_full_collection

bool G1CollectedHeap::do_full_collection(bool explicit_gc,
                                         bool clear_all_soft_refs,
                                         bool do_maximum_compaction) {
  assert_at_safepoint_on_vm_thread();
  //檢查jni lock
  if (GCLocker::check_active_before_gc()) {
    // Full GC was not completed.
    return false;
  }
  //判斷系統(tǒng)是否需要回收所有軟連接,主要看空間緊急程度
  const bool do_clear_all_soft_refs = clear_all_soft_refs ||
      soft_ref_policy()->should_clear_all_soft_refs();

  G1FullCollector collector(this, explicit_gc, do_clear_all_soft_refs, do_maximum_compaction);
  GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause(), true);
  //準備階段,主要是打印日志,停止cycle,停止并發(fā)標記,關(guān)閉活躍區(qū)域等
  collector.prepare_collection();
  collector.collect();
  //清理標記狀態(tài),記錄full gc結(jié)束日志等
  collector.complete_collection();

  // Full collection was successfully completed.
  return true;
}

full gc分為四個階段,對應(yīng)四個task,看對應(yīng)的work方法即可
G1FullGCMarkTask,G1FullGCPrepareTask,G1FullGCAdjustTask,G1FullGCCompactTask

void G1FullCollector::collect() {
  //標記,<<深入理解jvm虛擬機>>書上沒看到這種full gc標記過程
  phase1_mark_live_objects();
  verify_after_marking();

  // Don't add any more derived pointers during later phases
  //棧上的派生類指針表進行關(guān)閉
  deactivate_derived_pointers();
  //壓縮準備,判斷region空間是否需要壓縮,存入一個隊列compaction queue
  phase2_prepare_compaction();
  //指針調(diào)整,新region地址更新
  phase3_adjust_pointers();
  //壓縮region,處理第二步的東西
  phase4_do_compaction();
}

phase1_mark_live_objects

使用到了gc線程來進行的標記,就是初始化g1heap出現(xiàn)的_worker,線程中再使用G1FullGCMarker的線程

void G1FullCollector::phase1_mark_live_objects() {
  // Recursively traverse all live objects and mark them.
  GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer());

  {
    // Do the actual marking.
    //標記,不是并發(fā)的,在prepare階段concurrent_cycle_abort關(guān)了
    G1FullGCMarkTask marking_task(this);
    //實際調(diào)用就是task的work方法
    run_task(&marking_task);
  }

  { //引用處理器ReferenceProcessor,一種是并發(fā)的_ref_processor_cm還有就是這里的_ref_processor_stw
    //stw的開啟會關(guān)閉cm的,并且開啟單單線程,full gc中發(fā)現(xiàn)任何引用都會記錄進來
    uint old_active_mt_degree = reference_processor()->num_queues();
    reference_processor()->set_active_mt_degree(workers());
    GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", scope()->timer());
    // Process reference objects found during marking.
    //標記過程中出現(xiàn)的引用處理
    ReferenceProcessorPhaseTimes pt(scope()->timer(), reference_processor()->max_num_queues());
    G1FullGCRefProcProxyTask task(*this, reference_processor()->max_num_queues());
    //處理引用,按照軟強弱虛的順序處理
    const ReferenceProcessorStats& stats = reference_processor()->process_discovered_references(task, pt);
    scope()->tracer()->report_gc_reference_stats(stats);
    pt.print_all_references();
    assert(marker(0)->oop_stack()->is_empty(), "Should be no oops on the stack");

    reference_processor()->set_active_mt_degree(old_active_mt_degree);
  }

  // Weak oops cleanup.
  // 對象只有一個弱引用的話就要被回收
  // 這里處理會開多個線程,將弱引用地址所指的對象循環(huán)查看,不是空的且不是存活的對象就釋放引用
  {
    GCTraceTime(Debug, gc, phases) debug("Phase 1: Weak Processing", scope()->timer());
    WeakProcessor::weak_oops_do(_heap->workers(), &_is_alive, &do_nothing_cl, 1);
  }

  // Class unloading and cleanup.
  // classloader卸載class,要從符號表移除
  if (ClassUnloading) {
    GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
    // Unload classes and purge the SystemDictionary.
    bool purged_class = SystemDictionary::do_unloading(scope()->timer());
    _heap->complete_cleaning(&_is_alive, purged_class);
  }

  scope()->tracer()->report_object_count_after_gc(&_is_alive);
}

多線程處理標記,GcRoots,注意這里不是說傳統(tǒng)意義的多線程來處理,而是我們需要對每個線程進行處理

void G1FullGCMarkTask::work(uint worker_id) {
  Ticks start = Ticks::now();
  ResourceMark rm;
  G1FullGCMarker* marker = collector()->marker(worker_id);
  MarkingCodeBlobClosure code_closure(marker->mark_closure(), !CodeBlobToOopClosure::FixRelocations);
  //ClassUnloading默認為true
  if (ClassUnloading) {
  //處理gcRoots
    _root_processor.process_strong_roots(marker->mark_closure(),
                                         marker->cld_closure(),
                                         &code_closure);
  } else {
    _root_processor.process_all_roots(marker->mark_closure(),
                                      marker->cld_closure(),
                                      &code_closure);
  }

  // Mark stack is populated, now process and drain it.
  //之前遍歷roots生成的stack進行抽取處理
  //通過mark word將存活的對象記錄到_mark_stats_cache
  marker->complete_marking(collector()->oop_queue_set(), collector()->array_queue_set(), &_terminator);
  marker->flush_mark_stats_cache();

  // This is the point where the entire marking should have completed.
  assert(marker->oop_stack()->is_empty(), "Marking should have completed");
  assert(marker->objarray_stack()->is_empty(), "Array marking should have completed");
  log_task("Marking task", worker_id, start);
}

process_strong_roots標記gcRoots

void G1RootProcessor::process_strong_roots(OopClosure* oops,
                                           CLDClosure* clds,
                                           CodeBlobClosure* blobs) {
  StrongRootsClosures closures(oops, clds, blobs);
  //1.清除本地方法nmethod線程棧外的對象
  //2.重新映射對象
  //3.標記存活對象
  process_java_roots(&closures, NULL, 0);
  process_vm_roots(&closures, NULL, 0);

  // CodeCache is already processed in java roots
  // refProcessor is not needed since we are inside a safe point
  _process_strong_tasks.all_tasks_claimed(G1RP_PS_CodeCache_oops_do,
                                          G1RP_PS_refProcessor_oops_do);
}

先看StrongRootsClosures closures(oops, clds, blobs);
這里三個參數(shù)的類型為G1MarkAndPushClosure,CLDToOopClosure,MarkingCodeBlobClosure
對應(yīng)獲取方法strong_oops(),strong_clds(),strong_codeblobs()
對應(yīng)的root為java引用,類加載器對象,方法對象
實際運行的就是這些closure

complete_marking 處理前一步從強引用,類加載器,方法區(qū)獲得的gcRoots對象

void G1FullGCMarker::complete_marking(OopQueueSet* oop_stacks,
                                      ObjArrayTaskQueueSet* array_stacks,
                                      TaskTerminator* terminator) {
  do {
    //處理標記
    drain_stack();
    ObjArrayTask steal_array;
    //從其他worker線程取任務(wù)繼續(xù)處理
    if (array_stacks->steal(_worker_id, steal_array)) {
      follow_array_chunk(objArrayOop(steal_array.obj()), steal_array.index());
    } else {
      oop steal_oop;
      if (oop_stacks->steal(_worker_id, steal_oop)) {
        follow_object(steal_oop);
      }
    }
  } while (!is_empty() || !terminator->offer_termination());
}
//處理
void G1FullGCMarker::drain_stack() {
  do {
    oop obj;
    //從之前gcroots標記的_oop_stack獲取對象到obj
    while (pop_object(obj)) {
      assert(_bitmap->is_marked(obj), "must be marked");
      //標記成員,也就是可達對象,mark_push后再while循環(huán),不可達的對象最后會被回收
      follow_object(obj);
    }
    // Process ObjArrays one at a time to avoid marking stack bloat.
    ObjArrayTask task;
    if (pop_objarray(task)) {
      follow_array_chunk(objArrayOop(task.obj()), task.index());
    }
  } while (!is_empty());
}

phase2_prepare_compaction

直接看G1FullGCPrepareTask核心代碼

bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
  bool force_not_compacted = false;
  if (should_compact(hr)) {
  //首先通過hrm region管理器查看對應(yīng)region是否已經(jīng)pinned(歸檔或者是大對象),再檢查region壓縮的臨界值
    assert(!hr->is_humongous(), "moving humongous objects not supported.");
    //到達臨界值沒有鎖定的region放入隊列
    prepare_for_compaction(hr);
  } else {
    // There is no need to iterate and forward objects in pinned regions ie.
    // prepare them for compaction. The adjust pointers phase will skip
    // work for them.
    assert(hr->containing_set() == nullptr, "already cleared by PrepareRegionsClosure");
    if (hr->is_humongous()) {
      oop obj = cast_to_oop(hr->humongous_start_region()->bottom());
      //大對象檢查是否標記,不在標記的進行回收且放入回收隊列
      if (!_bitmap->is_marked(obj)) {
        free_pinned_region<true>(hr);
      }
    } else if (hr->is_open_archive()) {
      bool is_empty = _collector->live_words(hr->hrm_index()) == 0;
      if (is_empty) {
        free_pinned_region<false>(hr);
      }
    } else if (hr->is_closed_archive()) {
      // nothing to do with closed archive region
    } else {
      //MarkSweepDeadRatio默認5
      assert(MarkSweepDeadRatio > 0,
             "only skip compaction for other regions when MarkSweepDeadRatio > 0");

      // Too many live objects; skip compacting it.
      _collector->update_from_compacting_to_skip_compacting(hr->hrm_index());
      //region如果是年輕代的,需要創(chuàng)建Block Offset Table
      if (hr->is_young()) {
        // G1 updates the BOT for old region contents incrementally, but young regions
        // lack BOT information for performance reasons.
        // Recreate BOT information of high live ratio young regions here to keep expected
        // performance during scanning their card tables in the collection pauses later.
        hr->update_bot();
      }
      log_trace(gc, phases)("Phase 2: skip compaction region index: %u, live words: " SIZE_FORMAT,
                            hr->hrm_index(), _collector->live_words(hr->hrm_index()));
    }
  }

  // Reset data structures not valid after Full GC.
  //清除rem_set與cardtable信息
  reset_region_metadata(hr);

  return false;
}

如果準備階段發(fā)現(xiàn)!task.has_freed_regions()
regions不夠用,就需要用到serial的gc,調(diào)用prepare_serial_compaction

phase3_adjust_pointers

G1FullGCAdjustTask

void G1FullGCAdjustTask::work(uint worker_id) {
  Ticks start = Ticks::now();
  ResourceMark rm;

  // Adjust preserved marks first since they are not balanced.
  G1FullGCMarker* marker = collector()->marker(worker_id);\
  //調(diào)整stack中的對象地址,前面的region已經(jīng)回收了
  marker->preserved_stack()->adjust_during_full_gc();

  // Adjust the weak roots.
  if (!Atomic::cmpxchg(&_references_done, false, true)) {
    G1CollectedHeap::heap()->ref_processor_stw()->weak_oops_do(&_adjust);
  }

  AlwaysTrueClosure always_alive;
  _weak_proc_task.work(worker_id, &always_alive, &_adjust);

  CLDToOopClosure adjust_cld(&_adjust, ClassLoaderData::_claim_strong);
  CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations);
  //回到了第一個標記階段
  _root_processor.process_all_roots(&_adjust, &adjust_cld, &adjust_code);

  // Now adjust pointers region by region
  //逐個region進行處理
  G1AdjustRegionClosure blk(collector(), worker_id);
  G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&blk, &_hrclaimer, worker_id);
  log_task("Adjust task", worker_id, start);
}

phase4_do_compaction

void G1FullGCCompactTask::work(uint worker_id) {
  Ticks start = Ticks::now();
  GrowableArray<HeapRegion*>* compaction_queue = collector()->compaction_point(worker_id)->regions();
  for (GrowableArrayIterator<HeapRegion*> it = compaction_queue->begin();
       it != compaction_queue->end();
       ++it) {
    //將標記對象取出后,移動到目標地址,隨后清除next_mark_bitmap
    compact_region(*it);
  }
  //重新設(shè)置region是否需要壓縮
  G1ResetSkipCompactingClosure hc(collector());
  G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id);
  log_task("Compaction task", worker_id, start);
}

壓縮就是復(fù)制,每一個對象存了新地址的

size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) {
  size_t size = obj->size();
  HeapWord* destination = cast_from_oop<HeapWord*>(obj->forwardee());
  if (destination == NULL) {
    // Object not moving
    return size;
  }

  // copy object and reinit its mark
  HeapWord* obj_addr = cast_from_oop<HeapWord*>(obj);
  assert(obj_addr != destination, "everything in this pass should be moving");
  Copy::aligned_conjoint_words(obj_addr, destination, size);
//初始化就是更新對象mark word
  cast_to_oop(destination)->init_mark();
  assert(cast_to_oop(destination)->klass() != NULL, "should have a class");

  return size;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容