JVM G1 源码分析(四)- Dirty Card Queue Set

1. 简介

在上篇文章中,我们介绍了RSet的原理,当对象引用关系变化时,都需要更新RSet。为了不影响Mutator的性能,RSet的更新通常是异步进行的,这一异步更新操作需要引入DCQS(Dirty Card Queue Set)结构。

本文将分析DCQS的原理。

2. DCQS

2.1 写入DCQS

JVM声明了一个全局的静态结构G1BarrierSet,其中包含两个Queue Set,DirtyCardQueueSet和G1SATBMarkQueueSet,分别用于处理DCQS和STAB。

g1BarrierSet.hpp

class G1BarrierSet: public CardTableBarrierSet {
  friend class VMStructs;
 private:
  BufferNode::Allocator _satb_mark_queue_buffer_allocator;
  BufferNode::Allocator _dirty_card_queue_buffer_allocator;
  G1SATBMarkQueueSet _satb_mark_queue_set;
  DirtyCardQueueSet _dirty_card_queue_set;
}
  • _dirty_card_queue_set即为全局的DCQS

g1BarrierSet.cpp

G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
  CardTableBarrierSet(make_barrier_set_assembler<G1BarrierSetAssembler>(),
                      make_barrier_set_c1<G1BarrierSetC1>(),
                      make_barrier_set_c2<G1BarrierSetC2>(),
                      card_table,
                      BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)),
  _satb_mark_queue_buffer_allocator(G1SATBBufferSize, SATB_Q_FL_lock),
  _dirty_card_queue_buffer_allocator(G1UpdateBufferSize, DirtyCardQ_FL_lock),
  _satb_mark_queue_set(),
  _dirty_card_queue_set()
{}
  • DCQ队列长度为G1UpdateBufferSize(默认256),超过阈值时该DCQ会被写入DCQS

DCQ的入队逻辑也在g1BarrierSet.cpp

void G1BarrierSet::write_ref_field_post_slow(volatile jbyte* byte) {
  // In the slow path, we know a card is not young
  assert(*byte != G1CardTable::g1_young_card_val(), "slow path invoked without filtering");
  OrderAccess::storeload();
  if (*byte != G1CardTable::dirty_card_val()) {
    *byte = G1CardTable::dirty_card_val();
    Thread* thr = Thread::current();
    if (thr->is_Java_thread()) {
      G1ThreadLocalData::dirty_card_queue(thr).enqueue(byte);
    } else {
      MutexLockerEx x(Shared_DirtyCardQ_lock,
                      Mutex::_no_safepoint_check_flag);
      _dirty_card_queue_set.shared_dirty_card_queue()->enqueue(byte);
    }
  }
}
  • 如果当前线程是Mutator线程,则调用当前线程DCQ的enqueue方法
  • 否则,调用DCQS的_shared_dirty_card_queue的enqueue方法,_shared_dirty_card_queue是全局变量,调用enqueue前需要加锁

入队最后都会调用到DirtyCardQueue的enqueue方法,DirtyCardQueue是PtrQueue的子类,因此实际会调用PtrQueue的enqueue方法。
ptrQueue.hpp

  void enqueue(void* p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值