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

   目录

1、expand / shrink 

2、allocate / par_allocate / expand_and_allocate /allocation_limit_reached

3、 promote / par_promote / par_promote_alloc_done / promotion_attempt_is_safe / promotion_failure_occurred

4、save_marks / no_allocs_since_save_marks / oop_since_save_marks_iterate

5、space_iterate / oop_iterate / safe_object_iterate / object_iterate / younger_refs_iterate

6、sample_eden_chunk

7、gc_prologue / gc_epilogue

8、should_collect / should_concurrent_collect / is_too_full / collect

9、compute_new_size / compute_new_size_free_list


本篇继续上一篇《Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(二) 源码解析》讲解ConcurrentMarkSweepGeneration的其他关键方法的实现。

1、expand / shrink 

      这两个方法用于老年代的扩容和缩容,底层都是基于VirtualSpace,执行成功后再重置BlockOffsetSharedArray,重置BarrierSet,重置end属性,其实现如下:

bool ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes) {
  //底层实现依赖于子类的grow_by和grow_to_reserved方法
  return CardGeneration::expand(bytes, expand_bytes);
}

void ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes,
  CMSExpansionCause::Cause cause)
{

  bool success = expand(bytes, expand_bytes);

  if (success) {
    //记录扩展的原因,shouldConcurrentCollect()方法使用
    set_expansion_cause(cause);
    if (PrintGCDetails && Verbose) {
      gclog_or_tty->print_cr("Expanded CMS gen for %s",
        CMSExpansionCause::to_string(cause));
    }
  }
}

void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}

bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) {
  //校验获取了Heap_lock锁
  assert_locked_or_safepoint(Heap_lock);
  //通过VirtualSpace扩容,即新申请指定大小的内存
  bool result = _virtual_space.expand_by(bytes);
  if (result) {
    //申请成功,获取当前扩容后的内存容量
    size_t new_word_size =
      heap_word_size(_virtual_space.committed_size());
    MemRegion mr(_cmsSpace->bottom(), new_word_size);
    //重置bts对应的内存区域
    _bts->resize(new_word_size);  // resize the block offset shared array
    //重置bs对应的内存区域
    Universe::heap()->barrier_set()->resize_covered_region(mr);
    //校验获取了freelistLock,即应该是填充FreeList时导致的扩容
    _cmsSpace->assert_locked(freelistLock());
    //重置end
    _cmsSpace->set_end((HeapWord*)_virtual_space.high());

    if (UsePerfData) {
      //更新计数器
      _space_counters->update_capacity();
      _gen_counters->update_all();
    }

    if (Verbose && PrintGC) {
      size_t new_mem_size = _virtual_space.committed_size();
      size_t old_mem_size = new_mem_size - bytes;
      gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K",
                    name(), old_mem_size/K, bytes/K, new_mem_size/K);
    }
  }
  return result;
}

bool ConcurrentMarkSweepGeneration::grow_to_reserved() {
  assert_locked_or_safepoint(Heap_lock);
  bool success = true;
  //获取剩余未分配内存的空间
  const size_t remaining_bytes = _virtual_space.uncommitted_size();
  if (remaining_bytes > 0) {
    //将剩余空间一次扩容
    success = grow_by(remaining_bytes);
  }
  return success;
}

Mutex* ConcurrentMarkSweepGeneration::freelistLock() const {
  return cmsSpace()->freelistLock();
}

void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) {
  assert_locked_or_safepoint(ExpandHeap_lock);
  //通过VirtualSpace缩容
  _virtual_space.shrink_by(bytes);
  //重置end 
  _cmsSpace->set_end((HeapWord*) _virtual_space.high());
  size_t new_word_size = heap_word_size(_cmsSpace->capacity());
  //重置bts
  _bts->resize(new_word_size);
  MemRegion mr(_cmsSpace->bottom(), new_word_size);
  //重置bs
  Universe::heap()->barrier_set()->resize_covered_region(mr);

  if (Verbose && PrintGC) {
    size_t new_mem_size = _virtual_space.committed_size();
    size_t old_mem_size = new_mem_size + bytes;
    gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
                  name(), old_mem_size/K, new_mem_size/K);
  }
}

void ConcurrentMarkSweepGeneration::shrink(size_t bytes) {
  assert_locked_or_safepoint(Heap_lock);
  //内存对齐
  size_t size = ReservedSpace::page_align_size_down(bytes);
  //只有执行过压缩,所有空闲空间都集中中尾部才能缩容
  if (size > 0 && did_compact()) {
    shrink_by(size);
  }
}

bool did_compact() { return _did_compact; }

其调用链如下:

2、allocate / par_allocate / expand_and_allocate /allocation_limit_reached

      allocate方法会获取freelistLock锁,然后从cmsSpace中分配指定大小的内存,如果此时后台GC进入Marking环节还需要将分配的内存地址标记成存活对象,避免被垃圾回收给清理掉了;因为allocate方法需要获取全局唯一的freelistLock锁所以也适用于并发环境,par_allocate的实现就是调用allocate方法;expand_and_allocate是当allocate返回NULL,即内存分配失败后调用的,会先扩容,再执行与allocate相同的内存分配逻辑。allocation_limit_reached方法时iCMS模式下年轻代通知老年代内存分配达到了soft_end,该方法返回一个新的soft_end地址,非iCMS模式下永远返回NULL。其实现如下:

HeapWord* ConcurrentMarkSweepGeneration::allocate(size_t size,
                                                  bool   tlab) {
  //通知CMS Thread让出CPU使用权限                                                
  CMSSynchronousYieldRequest yr;
  //获取freelistLock,从CompactibleFreeListSpace中分配内存都需要先获取该锁
  MutexLockerEx x(freelistLock(),
                  Mutex::_no_safepoint_check_flag);
  return have_lock_and_allocate(size, tlab);
}

HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size,
                                                  bool   tlab /* ignored */) {
  assert_lock_strong(freelistLock());
  //作内存对齐
  size_t adjustedSize = CompactibleFreeListSpace::adjustObjectSize(size);
  //从cmsSpace中分配指定大小的内存块
  HeapWord* res = cmsSpace()->allocate(adjustedSize);
  if (res != NULL) {
    //校验这是一个空闲内存块
    assert(oop(res)->klass_or_null() == NULL, "Object should be uninitialized here.");
    assert(!((FreeChunk*)res)->is_free(), "Error, block will look free but show wrong size");
    //如果GC进入Marking环节了,则将该地址标记成存活对象,避免被清理掉
    collector()->direct_allocated(res, adjustedSize);
    //增加_direct_allocated_words计数器
    _direct_allocated_words += adjustedSize;
  }
  return res;
}

void CMSCollector::direct_allocated(HeapWord* start, size_t size) {
  assert(_markBitMap.covers(start, size), "Out of bounds");
  //已经进入到标记清理环节,此时分配的地址start可能已经被处理过了,可能会被当做非存活对象给清理掉
  //所以需要将该地址打标成存活对象
  if (_collectorState >= Marking) {
    //获取BitMap的锁
    MutexLockerEx y(_markBitMap.lock(),
                    Mutex::_no_safepoint_check_flag);
    _markBitMap.mark(start);    //标记这个对象是存活的
    _markBitMap.mark(start + 1);      // 标记这个对象未初始化
    _markBitMap.mark(start + size - 1); //标记这个对象的结束地址,这样marking, precleaning or sweeping等处理时会跳过该对象
  }
  //校验oop未初始化
  assert(oop(start)->klass_or_null() == NULL, "_klass should be NULL");
}

//因为allocate方法执行过程中必须要获取全局唯一的freelistLock锁,所以也完全适用于并发环境下内存分配
HeapWord* par_allocate(size_t size, bool tlab) {
    return allocate(size, tlab);
  }

HeapWord*
ConcurrentMarkSweepGeneration::expand_and_allocate(size_t word_size,
                                                   bool   tlab,
                                                   bool   parallel) {
  CMSSynchronousYieldRequest yr;
  assert(!tlab, "Can't deal with TLAB allocation");
  MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag);
  //先扩展指定大小的内存,MinHeapDeltaBytes表示堆内存扩容或者缩容的最小内存,默认是128k,单位是字节
  expand(word_size*HeapWordSize, MinHeapDeltaBytes,
    CMSExpansionCause::_satisfy_allocation);
  //GCExpandToAllocateDelayMillis表示在内存扩展和内存分配动作之间的停顿,默认是0
  if (GCExpandToAllocateDelayMillis > 0) {
    os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
  }
  return have_lock_and_allocate(word_size, tlab);
}

HeapWord*
ConcurrentMarkSweepGeneration::allocation_limit_reached(Space* space,
                                             HeapWord* top,
                                             size_t word_sz)
{
  return collector()->allocation_limit_reached(space, top, word_sz);
}

HeapWord*
CMSCollector::allocation_limit_reached(Space* space, HeapWord* top,
                                       size_t word_size)
{
  if (CMSIncrementalMode && _icms_start_limit != space->end()) {
    if (top <= _icms_start_limit) {
      if (CMSTraceIncrementalMode) {
        space->print_on(gclog_or_tty);
        gclog_or_tty->stamp();
        gclog_or_tty->print_cr(" start limit top=" PTR_FORMAT
                               ", new limit=" PTR_FORMAT
                               " (" SIZE_FORMAT "%%)",
     
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值