当前位置: 首页>大数据>正文

ZGC源码解析(二)

概述

上文说到了触发ZGC的垃圾回收的几种场景,本文详细介绍下ZGC的具体步骤

ZDrvier线程

ZGC是有ZDriver负责实际的执行,相关代码如下:

void ZDriver::run_service() {
  // Main loop
  while (!should_terminate()) {
    // 堵塞方式等待GC请求
    const ZDriverRequest request = _gc_cycle_port.receive();
    if (request.cause() == GCCause::_no_gc) {
      continue;
    }
    // 执行GC
    gc(request);

    // 通知GC已经完成
    _gc_cycle_port.ack();
  }
}
void ZDriver::gc(const ZDriverRequest& request) {
  ZDriverGCScope scope(request);

  // 阶段1: Pause Mark Start
  pause_mark_start();

  // 阶段2: Concurrent Mark
  concurrent(mark);

  // 阶段3: Pause Mark End
  while (!pause_mark_end()) {
    // Phase 3.5: Concurrent Mark Continue
    concurrent(mark_continue);
  }

  // 阶段4: Concurrent Mark Free
  concurrent(mark_free);

  // 阶段5: Concurrent Process Non-Strong References
  concurrent(process_non_strong_references);

  // 阶段6: Concurrent Reset Relocation Set
  concurrent(reset_relocation_set);

  // 阶段7: Pause Verify
  pause_verify();

  // 阶段8: Concurrent Select Relocation Set
  concurrent(select_relocation_set);

  // 阶段9: Pause Relocate Start
  pause_relocate_start();

  // 阶段10: Concurrent Relocate
  concurrent(relocate);
}

gc函数中,以concurrent开头表示并发执行,pause表示需要暂停业务线程

阶段1(Pause Mark Start)

void ZHeap::mark_start() {
  // Flip address view
  flip_to_marked();

  // Retire allocating pages
  _object_allocator.retire_pages();

  // Reset allocated/reclaimed/used statistics
  _page_allocator.reset_statistics();

  // Reset encountered/dropped/enqueued statistics
  _reference_processor.reset_statistics();

  // Enter mark phase
  ZGlobalPhase = ZPhaseMark;

  // Reset marking information and mark roots
  _mark.start();

  // Update statistics
  ZStatHeap::set_at_mark_start(_page_allocator.stats());
}

可以看到ZGC的Pause Mark Start阶段所做的是只是修改状态位,重置统计数据,并不会实际的去标记root对象,因此速度是很快的;

阶段2(Concurrent Mark)

void ZMark::mark(bool initial) {
  if (initial) {
    ZMarkRootsTask task(this);
    _workers->run(&task);
  }

  ZMarkTask task(this);
  _workers->run(&task);
}

阶段2.1 ( Mark Roots)

并发标记阶段传入的initial=true,表示要先标记GC ROOTS;

  ZMarkOopClosure            _cl;
  ZMarkCLDClosure            _cld_cl;
  ZMarkThreadClosure         _thread_cl;
  ZMarkNMethodClosure        _nm_cl;

virtual void work() {
   _oop_storage_set.apply(&cl);
  _class_loader_data_graph.apply(&cld_cl);
  _java_threads.apply(&thread_cl);
  if (!ClassUnloading) {
    _nmethods.apply(&nm_cl);
  }
    _mark->flush_and_free();
  }

这里的_oop_storage_set包含哪些内容呢?_oop_storage_set包括5个strong类型和10个weak类型的全局变量;_class_loader_data_graph和_java_threads分别表示类加载器和java线程栈,_nmethods表示JIT编译之后的方法;

 static const uint strong_count = 4 JVMTI_ONLY(+ 1);
 static const uint weak_count = 8 JVMTI_ONLY(+ 1) JFR_ONLY(+ 1);

1. Universe::_vm_global = OopStorageSet::create_strong("VM Global", mtInternal);
2. _thread_oop_storage = OopStorageSet::create_strong("Thread OopStorage", mtThread);
3. _thread_service_storage = OopStorageSet::create_strong("ThreadService OopStorage", mtServiceability);
4. JNIHandles::_global_handles = OopStorageSet::create_strong("JNI Global", mtInternal);
5. _jvmti_oop_storage = OopStorageSet::create_strong("JVMTI OopStorage", mtServiceability);


1. Universe::_vm_weak = OopStorageSet::create_weak("VM Weak", mtInternal);
2. JNIHandles::_weak_global_handles = OopStorageSet::create_weak("JNI Weak", mtInternal);
3. _oop_storage = OopStorageSet::create_weak("StringTable Weak", mtSymbol);
4. _storages[0] = OopStorageSet::create_weak("StringDedup Requests0 Weak", mtStringDedup);
5. _storages[1] = OopStorageSet::create_weak("StringDedup Requests1 Weak", mtStringDedup);
6. _table_storage = OopStorageSet::create_weak("StringDedup Table Weak", mtStringDedup);
7. _oop_storage = OopStorageSet::create_weak("ResolvedMethodTable Weak", mtClass);
8. _oop_storage = OopStorageSet::create_weak("ObjectSynchronizer Weak", mtSynchronizer);
9. _weak_tag_storage  = OopStorageSet::create_weak("JVMTI Tag Weak OopStorage", mtServiceability);
10. _oop_storage = OopStorageSet::create_weak("Weak JFR Old Object Samples", mtTracing);


  #define ENUMERATOR_VALUE_RANGE(T, Start, End)                           \
  template<> struct EnumeratorRange<T> {                                \
    static constexpr EnumeratorRangeImpl::Underlying<T> _start{Start};  \
    static constexpr EnumeratorRangeImpl::Underlying<T> _end{End};      \
  };


ENUMERATOR_VALUE_RANGE(OopStorageSet::StrongId,
                       OopStorageSet::strong_start,
                       OopStorageSet::strong_end);

ENUMERATOR_VALUE_RANGE(OopStorageSet::WeakId,
                       OopStorageSet::weak_start,
                       OopStorageSet::weak_end);

ENUMERATOR_VALUE_RANGE(OopStorageSet::Id,
                       OopStorageSet::all_start,
                       OopStorageSet::all_end);

对于上述的全局变量、java线程栈、类加载器和JIT编译方法,最终是通过ZMarkOopClosure来进行标记的:

class ZMarkOopClosure : public OopClosure {
  virtual void do_oop(oop* p) {
    const oop o = Atomic::load(p);
    const uintptr_t addr = ZOop::to_address(o);
    if (ZAddress::is_good(addr)) {
      // Mark through good oop
      mark_barrier_on_oop_slow_path(addr);
    } else {
      // Mark through bad oop
      barrier<is_good_or_null_fast_path, mark_barrier_on_oop_slow_path>(p, o);
    }
  }

  virtual void do_oop(narrowOop* p) {
    ShouldNotReachHere();
  }
};
uintptr_t ZBarrier::mark_barrier_on_oop_slow_path(uintptr_t addr) {
  uintptr_t good_addr;

  if (ZAddress::is_marked(addr)) {
    // Already marked, but try to mark though anyway
    good_addr = ZAddress::good(addr);
  } else if (ZAddress::is_remapped(addr)) {
    // Already remapped, but also needs to be marked
    good_addr = ZAddress::good(addr);
  } else {
    // Needs to be both remapped and marked
    good_addr = remap(addr);
  }

  // 标记
  ZHeap::heap()->mark_object<true, true, false, false>(good_addr);
  return good_addr;
}
inline void ZMark::mark_object(uintptr_t addr) {
   ZPage* const page = _page_table->get(addr);
   if (page->is_allocating()) {
     // Already implicitly marked
     return;
   }

    bool inc_live = false;
    // Try mark object
    if (!page->mark_object(addr, false, inc_live)) {
      // Already marked
      return;
    }
  

  // Push
  ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());
  ZMarkStripe* const stripe = _stripes.stripe_for_addr(addr);
  ZMarkStackEntry entry(addr, false, inc_live, true, false);
  stacks->push(&_allocator, &_stripes, stripe, entry, false);
}

可以看到GC ROOT的标记相对比较简单,会更新page对象的_livemap,同时会将对象包装成ZMarkStackEntry,放到当前标记线程的ZMarkThreadLocalStacks中,如果当前线程已满,则放到全局的条带stripe中去;
注意的,对于GC ROOTS,ZMarkStackEntry的finalizable=false,follow=true,mark=false;

阶段2.2 ( Mark)

GC ROOTs标记完成之后,开始进行剩余其他对象的标记:

void ZMark::work() {
  ZMarkCache cache(_stripes.nstripes());
  ZMarkStripe* const stripe = _stripes.stripe_for_worker(_nworkers, ZThread::worker_id());
  ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());

  work_without_timeout(&cache, stripe, stacks);

  // Flush and publish stacks
  stacks->flush(&_allocator, &_stripes);

  // Free remaining stacks
  stacks->free(&_allocator);
}

从2.1知道,标记GC ROOTS的时候,会将存活的对象放到标记线程的ZMarkThreadLocalStacks或者全局的条带中去;此处会取出GC ROOTS,遍历成员,进行标记:

void ZMark::work_without_timeout(ZMarkCache* cache, ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks) {
  ZStatTimer timer(ZSubPhaseConcurrentMark);
  ZMarkNoTimeout no_timeout;

  for (;;) {
    if (!drain(stripe, stacks, cache, &no_timeout)) {
      break;
    }

   //试图从其他的条带窃取任务,如果成功,则继续标记
    if (try_steal(stripe, stacks)) {
      continue;
    }
   //如果是0号worker线程,通过handshake方式暂停其他线程,将线程的ZMarkThreadLocalStacks刷新到全局的条带中
    if (try_proactive_flush()) {
      continue;
    }
   //尝试结束并发标记阶段
    if (try_terminate()) {
      break;
    }
  }
}
bool ZMark::drain(ZMarkStripe* stripe, ZMarkThreadLocalStacks* stacks, ZMarkCache* cache, T* timeout) {
  ZMarkStackEntry entry;

  // Drain stripe stacks
  while (stacks->pop(&_allocator, &_stripes, stripe, entry)) {
    mark_and_follow(cache, entry);

    // Check timeout
    if (timeout->has_expired()) {
      // Timeout
      return false;
    }
  }

  // Success
  return !timeout->has_expired();
}

真正的执行标记的路径见mark_and_follow:

void ZMark::mark_and_follow(ZMarkCache* cache, ZMarkStackEntry entry) {
  // Decode flags
  const bool finalizable = entry.finalizable();
  const bool partial_array = entry.partial_array();

  if (partial_array) {
    follow_partial_array(entry, finalizable);
    return;
  }

  // Decode object address and additional flags
  const uintptr_t addr = entry.object_address();
  const bool mark = entry.mark();
  bool inc_live = entry.inc_live();
  const bool follow = entry.follow();

  ZPage* const page = _page_table->get(addr);
  // 检查_livemap,如果发现已经标记过,则忽略
  if (mark && !page->mark_object(addr, finalizable, inc_live)) {
    return;
  }

  // 如果需要更新存活信息
  if (inc_live) {
    const size_t size = ZUtils::object_size(addr);
    const size_t aligned_size = align_up(size, page->object_alignment());
    cache->inc_live(page, aligned_size);
  }

  // 是否需要继续标记对象的成员
  if (follow) {
    if (is_array(addr)) {
      follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable);
    } else {
      follow_object(ZOop::from_address(addr), finalizable);
    }
  }
}
void ZMark::follow_object(oop obj, bool finalizable) {
  if (finalizable) {
    ZMarkBarrierOopClosure<true > cl;
    obj->oop_iterate(&cl);
  } else {
    ZMarkBarrierOopClosure<false> cl;
    obj->oop_iterate(&cl);
  }
}

obj.oop_iterate调用的是oopDesc::oop_iterate(OopClosureType* cl) { OopIteratorClosureDispatch::oop_oop_iterate(cl, this, klass()); },根据obj对象的不同类型,最终调用的方法也不一样:

  1. 如果obj的类型是InstanceKlass,最终调用
template <typename T, class OopClosureType>
ALWAYSINLINE void InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
  if (Devirtualizer::do_metadata(closure)) {
    Devirtualizer::do_klass(closure, this);
  }

  oop_oop_iterate_oop_maps<T>(obj, closure);
}
  1. 如果obj的类型是InstanceRefKlass,即java/lang/ref/Reference子类,最终调用
template <typename T, class OopClosureType>
void InstanceRefKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
  InstanceKlass::oop_oop_iterate<T>(obj, closure);

  oop_oop_iterate_ref_processing<T>(obj, closure);//引用对象处理
}

从上面的源码看到,如果对象是Reference类型,会进行额外的处理:

void InstanceRefKlass::oop_oop_iterate_discovery(oop obj, ReferenceType type, OopClosureType* closure, Contains& contains) {
  // 如果referent对象是活跃的,或者根据soft_reference_policy,本次不需要回收,直接返回
  if (try_discover<T>(obj, type, closure)) {
    return;
  }

  // 处理referent对象
  do_referent<T>(obj, closure, contains);
//_discovered_list
  do_discovered<T>(obj, closure, contains);
}
  1. 如果obj的类型是InstanceMirrorKlass,最终调用
void InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
  InstanceKlass::oop_oop_iterate<T>(obj, closure);

  if (Devirtualizer::do_metadata(closure)) {
    Klass* klass = java_lang_Class::as_Klass_raw(obj);
    if (klass != NULL) {
      if (klass->class_loader_data() == NULL) {
        return;
      } else if (klass->is_instance_klass() && klass->class_loader_data()->has_class_mirror_holder()) {
        Devirtualizer::do_cld(closure, klass->class_loader_data());
      } else {
        Devirtualizer::do_klass(closure, klass);
      }
    } 
  }

  oop_oop_iterate_statics<T>(obj, closure);
}
  1. 如果obj的类型是InstanceClassLoaderKlass,最终调用
template <typename T, class OopClosureType>
inline void InstanceClassLoaderKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
  InstanceKlass::oop_oop_iterate<T>(obj, closure);

  if (Devirtualizer::do_metadata(closure)) {
    ClassLoaderData* cld = java_lang_ClassLoader::loader_data_raw(obj);
    if (cld != NULL) {
      Devirtualizer::do_cld(closure, cld);
    }
  }
}
  1. 如果obj的类型是ObjArrayKlass,最终调用
void ZMark::follow_array(uintptr_t addr, size_t size, bool finalizable) {
  if (size <= ZMarkPartialArrayMinSize) {
    follow_small_array(addr, size, finalizable);
  } else {
    follow_large_array(addr, size, finalizable);
  }
}

https://www.xamrdz.com/bigdata/7ea1995191.html

相关文章: