Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(二) 源码解析

  目录

一、ModUnionClosure / ModUnionClosurePar

二、CMSIsAliveClosure / CMSParKeepAliveClosure

三、CFLS_LAB

1、构造方法和modify_initialization

2、alloc

3、retire

4、 compute_desired_plab_size

四、ConcurrentMarkSweepGeneration

1、定义

2、构造方法和ref_processor_init

3、 ConcGCThreads / ParallelGCThreads


本篇博客继续上一篇《Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(一) 源码解析》讲解其他相关类的实现和使用。

一、ModUnionClosure / ModUnionClosurePar

      这两个类的定义都在concurrentMarkSweepGeneration.hpp中,用来遍历MemRegion,将其在BitMap对应的内存区域打标,其类继承关系如下:

其核心do_MemRegion方法的实现如下:

 

_t就是构造方法传入的CMSBitMap指针。 

二、CMSIsAliveClosure / CMSParKeepAliveClosure

     CMSIsAliveClosure用于判断某个对象是否是存活的,CMSParKeepAliveClosure用于将某个对象标记成存活的,底层都是依赖于BitMap,其实现如下:

CMSIsAliveClosure(MemRegion span,
                    CMSBitMap* bit_map):
    _span(span), //span表示老年代对应的内存区域
    _bit_map(bit_map) //CMSBitMap引用
  {
    assert(!span.is_empty(), "Empty span could spell trouble");
  }

bool CMSIsAliveClosure::do_object_b(oop obj) {
  HeapWord* addr = (HeapWord*)obj;
  //BitMap中打标则认为其是存活的
  return addr != NULL &&
         (!_span.contains(addr) || _bit_map->isMarked(addr));
}

CMSParKeepAliveClosure::CMSParKeepAliveClosure(CMSCollector* collector,
  MemRegion span, CMSBitMap* bit_map, OopTaskQueue* work_queue):
   _span(span), //老年代对应的内存区域
   _bit_map(bit_map), //老年代的BitMap
   _work_queue(work_queue), //执行任务的队列
   _mark_and_push(collector, span, bit_map, work_queue), //CMSInnerParMarkAndPushClosure实例
   _low_water_mark(MIN2((uint)(work_queue->max_elems()/4),
                       //CMSWorkQueueDrainThreshold表示CMSWorkQueue的阈值,默认是10
                        (uint)(CMSWorkQueueDrainThreshold * ParallelGCThreads))) //_work_queue的最大容量
{ }

void CMSKeepAliveClosure::do_oop(oop* p)       { CMSKeepAliveClosure::do_oop_work(p); }

void CMSKeepAliveClosure::do_oop(narrowOop* p) { CMSKeepAliveClosure::do_oop_work(p); }

void CMSParKeepAliveClosure::do_oop(oop obj) {
  HeapWord* addr = (HeapWord*)obj;
  //如果addr在老年代中且没有打标
  if (_span.contains(addr) &&
      !_bit_map->isMarked(addr)) {
    //如果打标成功,因为其他线程可能已经完成打标了,所以可能返回false
    if (_bit_map->par_mark(addr)) {
      //将obj放入队列中
      bool res = _work_queue->push(obj);
      assert(res, "Low water mark should be much less than capacity");
      //如果_work_queue中的oop超过指定容量了,则处理一部分
      trim_queue(_low_water_mark);
    } // Else, another thread got there first
  }
}

void CMSParKeepAliveClosure::trim_queue(uint max) {
  //如果待处理的oop过多
  while (_work_queue->size() > max) {
    oop new_oop;
    //弹出一个待处理的oop
    if (_work_queue->pop_local(new_oop)) {
      assert(new_oop != NULL && new_oop->is_oop(), "Expected an oop");
      assert(_bit_map->isMarked((HeapWord*)new_oop),
             "no white objects on this stack!");
      assert(_span.contains((HeapWord*)new_oop), "Out of bounds oop");
      //遍历该oop所引用的其他oop
      new_oop->oop_iterate(&_mark_and_push);
    }
  }
}

三、CFLS_LAB

      CFLS_LAB定义在同目录下的compactibleFreeListSpace.hpp中,是老年代并行GC下本地线程的内存分配缓存,其包含的属性如下:

  • CompactibleFreeListSpace* _cfls; //关联的CompactibleFreeListSpace实例
  • AdaptiveFreeList<FreeChunk>  _indexedFreeList[CompactibleFreeListSpace::IndexSetSize]; //缓存的不同大小的FreeList数组
  • static AdaptiveWeightedAverage  _blocks_to_claim  [CompactibleFreeListSpace::IndexSetSize]; //用来动态调整不同大小的FreeList中包含的FreeChunk内存块的个数
  • static size_t _global_num_blocks [CompactibleFreeListSpace::IndexSetSize];//这两个属性用于promote结束后统计不同大小剩余的FreeChunk的个数和曾经获取对应大小的FreeChunk的GC线程数,是_blocks_to_claim用来动态调整填充FreeList时填充的FreeChunk的个数
  • static uint   _global_num_workers[CompactibleFreeListSpace::IndexSetSize];
  • size_t        _num_blocks        [CompactibleFreeListSpace::IndexSetSize]; //用来记录不同大小的FreeList所包含的FreeChunk内存块的个数

重点关注以下方法的实现。

1、构造方法和modify_initialization

     modify_initialization是当命令行显示修改了CMSParPromoteBlocksToClaim或者OldPLABWeight的默认值时才会调用,其调用链如下:

该方法修改的是静态属性_blocks_to_claim,所以可以在启动时执行,Arguments::set_cms_and_parnew_gc_flags方法中的调用如下图:

两者的实现如下: 

CFLS_LAB::CFLS_LAB(CompactibleFreeListSpace* cfls) :
  _cfls(cfls)
{
  assert(CompactibleFreeListSpace::IndexSetSize == 257, "Modify VECTOR_257() macro above");
  //CompactibleFreeListSpace::set_cms_values方法把IndexSetStart初始化成MinChunkSize,IndexSetStride初始化成MinObjAlignment
  for (size_t i = CompactibleFreeListSpace::IndexSetStart;
       i < CompactibleFreeListSpace::IndexSetSize;
       i += CompactibleFreeListSpace::IndexSetStride) {
    _indexedFreeList[i].set_size(i);
    _num_blocks[i] = 0;
  }
}

static bool _CFLS_LAB_modified = false;

//实际调用时n传入的是OldPLABSize,wt传入的是OldPLABWeight
//OldPLABSize表示老年代中用于promotion的LAB的大小,默认值是1024
//OldPLABWeight表示重置CMSParPromoteBlocksToClaim时指数衰减的百分比,默认值是50
//CMSParPromoteBlocksToClaimb表示并行GC时重新填充LAB需要声明的内存块的个数
void CFLS_LAB::modify_initialization(size_t n, unsigned wt) {
  assert(!_CFLS_LAB_modified, "Call only once");
  _CFLS_LAB_modified = true;
  for (size_t i = CompactibleFreeListSpace::IndexSetStart;
       i < CompactibleFreeListSpace::IndexSetSize;
       i += CompactibleFreeListSpace::IndexSetStride) {
    _blocks_to_claim[i].modify(n, wt, true /* force */);
  }
}

#define VECTOR_257(x)                                                                                  \
  /* 1  2  3  4  5  6  7  8  9 1x 11 12 13 14 15 16 17 18 19 2x 21 22 23 24 25 26 27 28 29 3x 31 32 */ \
  {  x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,   \
     x }

//初始化
AdaptiveWeightedAverage CFLS_LAB::_blocks_to_claim[]    =
  VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CMSParPromoteBlocksToClaim));
size_t CFLS_LAB::_global_num_blocks[]  = VECTOR_257(0);
uint   CFLS_LAB::_global_num_workers[] = VECTOR_257(0);

构造方法的调用链如下:

2、alloc

      alloc方法用于分配指定大小的内存,如果大于IndexSetSize则尝试从_dictionary中分配,否则从本地的对应大小的FreeList中分配,如果对应FreeList中的空闲内存块的个数为0,则重新填充。其实现如下:

HeapWord* CFLS_LAB::alloc(size_t word_sz) {
  FreeChunk* res;
  assert(word_sz == _cfls->adjustObjectSize(word_sz), "Error");
  if (word_sz >=  CompactibleFreeListSpace::IndexSetSize) {
    //如果超过IndexSetSize,则获取_parDictionaryAllocLock锁,从_dictionary中分配
    MutexLockerEx x(_cfls->parDictionaryAllocLock(),
                    Mutex::_no_safepoint_check_flag);
    res = _cfls->getChunkFromDictionaryExact(word_sz);
    //分配失败返回NULL
    if (res == NULL) return NULL;
  } else {
    //获取对应大小的FreeList
    AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[word_sz];
    if (fl->count() == 0) {
      //如果fl是空则尝试重新填充
      get_from_global_pool(word_sz, fl);
      //填充失败返回Null
      if (fl->count() == 0) return NULL;
    }
    //获取链表头的FreeChunk
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值