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 "%%)",
                               p2i(top), p2i(_icms_stop_limit),
                               percent_of_space(space, _icms_stop_limit));
      }
      ConcurrentMarkSweepThread::start_icms();
      assert(top < _icms_stop_limit, "Tautology");
      //如果剩余空间足够
      if (word_size < pointer_delta(_icms_stop_limit, top)) {
        return _icms_stop_limit;
      }

      // _icms_stop_limit到top之间的空间不够
      if (CMSTraceIncrementalMode) {
        space->print_on(gclog_or_tty);
        gclog_or_tty->stamp();
        gclog_or_tty->print_cr(" +stop limit top=" PTR_FORMAT
                               ", new limit=" PTR_FORMAT
                               " (" SIZE_FORMAT "%%)",
                               p2i(top), p2i(space->end()),
                               percent_of_space(space, space->end()));
      }
      //停止垃圾回收,返回end
      ConcurrentMarkSweepThread::stop_icms();
      return space->end();
    }
    //top大于_icms_start_limit
    if (top <= _icms_stop_limit) {
      if (CMSTraceIncrementalMode) {
        space->print_on(gclog_or_tty);
        gclog_or_tty->stamp();
        gclog_or_tty->print_cr(" stop limit top=" PTR_FORMAT
                               ", new limit=" PTR_FORMAT
                               " (" SIZE_FORMAT "%%)",
                               top, space->end(),
                               percent_of_space(space, space->end()));
      }
      //停止垃圾收集
      ConcurrentMarkSweepThread::stop_icms();
      return space->end();
    }

    if (CMSTraceIncrementalMode) {
      space->print_on(gclog_or_tty);
      gclog_or_tty->stamp();
      gclog_or_tty->print_cr(" end limit top=" PTR_FORMAT
                             ", new limit=" PTR_FORMAT,
                             top, NULL);
    }
  }
  //CMSIncrementalMode为false,即默认配置下,当前方法永远返回NULL
  return NULL;
}

 其调用链如下:

3、 promote / par_promote / par_promote_alloc_done / promotion_attempt_is_safe / promotion_failure_occurred

      promote是在单线程时使用,将对象从年轻代复制到老年代,如果老年代内存不足则尝试扩容,复制成功后需要在_markBitMap和_modUnionTable打标,将复制的对象标记成存活的,已经被扫描过了。注意因为复制过去的对象本身已经完成初始化了,所以不需要将其标记成为初始化的,并且如果对象是一个数组,需要将数组的整个区域而不仅仅是头部地址打标。

     par_promote是并行GC时调用,整体逻辑跟promote相同,不过promote分配内存时使用的是当前线程对应的CMSParGCThreadState中的lab,执行promote 跟踪时也是使用当前线程对应的CMSParGCThreadState中的prom,避免多个线程同时从老年代分配内存造成锁竞争,从而提高并行promote的效率;如果当前线程的lab和prom的内存不足了,则同样需要扩容老年代,然后给lab和prom分配内存;另外跟单线程的promote相比,par_promote在复制对象时更加谨慎,不是一次复制完成,而是将对象头,klass和对象数据分开复制,每次复制结束都调用OrderAccess::storestore();在多个CPU间同步;跟单线程的promote一样,复制结束,需要在在_markBitMap和_modUnionTable打标。

    par_promote_alloc_done是并行GC线程执行promote结束后调用的,将当前GC线程的lab中的未使用内存归还给老年代。

     promotion_attempt_is_safe方法用于判断执行promote是否是安全的,主要判断历史promote的内存和传入的promote的最大内存是否超过当前老年代的可使用最大空间。

     promotion_failure_occurred是年轻代执行promote时,出现promote失败通知老年代执行必要的处理,在默认配置下不做任何处理,如果CMSDumpAtPromotionFailure只为true,可以dump当时的老年代内存使用情况。各方法的实现如下:

oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) {
  assert(obj_size == (size_t)obj->size(), "bad obj_size passed in");
  //校验获取freelistLock锁
  assert_lock_strong(freelistLock());
  //cmsSpace的promote方法就是从cmsSpace分配指定大小的内存,然后将obj拷贝过去
  oop res = _cmsSpace->promote(obj, obj_size);
  if (res == NULL) {
    //res等于NULL说明内存不足导致内存分配失败
    //计算需要扩容的大小
    size_t s = _cmsSpace->expansionSpaceRequired(obj_size);  // HeapWords
    //执行扩容
    expand(s*HeapWordSize, MinHeapDeltaBytes,
      CMSExpansionCause::_satisfy_promotion);
    assert(next_gen() == NULL, "assumption, based upon which no attempt "
                               "is made to pass on a possibly failing "
                               "promotion to next generation");
    //再次执行promote
    res = _cmsSpace->promote(obj, obj_size);
  }
  if (res != NULL) {
    //promote成功
    assert(obj->is_oop(), "Will dereference klass pointer below");
    //执行_markBitMap和_modUnionTable打标
    collector()->promoted(false,           // Not parallel
                          (HeapWord*)res, obj->is_objArray(), obj_size);
  }
  return res;
}

void CMSCollector::promoted(bool par, HeapWord* start,
                            bool is_obj_array, size_t obj_size) {
  assert(_markBitMap.covers(start), "Out of bounds");
 
  if (_collectorState >= Marking) {
    //如果GC已经到Marking环节,则需要将start标记成存活的,避免被清理掉
    if (par) {
      //这里不需要标记对应未初始化,因为该对象是从年轻代复制过来的,已经完成初始化了
      _markBitMap.par_mark(start);
    } else {
      _markBitMap.mark(start);
    }
    //
    assert(SafepointSynchronize::is_at_safepoint(),
           "expect promotion only at safepoints");

    if (_collectorState < Sweeping) {
      //在_modUnionTable中打标,表示被扫描过了
      if (is_obj_array) {
        //如果是数组,则需要将整个数组对应的内存区域标记成活的,注意数组的结束地址
        //需要按照card_size对齐
        MemRegion mr(start,
                     (HeapWord*)round_to((intptr_t)(start + obj_size),
                        CardTableModRefBS::card_size /* bytes */));
        if (par) {
          _modUnionTable.par_mark_range(mr);
        } else {
          _modUnionTable.mark_range(mr);
        }
      } else {  // not an obj array; we can just mark the head
        if (par) {
          _modUnionTable.par_mark(start);
        } else {
          _modUnionTable.mark(start);
        }
      }
    }
  }
}

oop
ConcurrentMarkSweepGeneration::par_promote(int thread_num,
                                           oop old, markOop m,
                                           size_t word_sz) {
  //获取thread_num对应的本地线程缓存
  CMSParGCThreadState* ps = _par_gc_thread_states[thread_num];
  PromotionInfo* promoInfo = &ps->promo;
  if (promoInfo->tracking() && !promoInfo->ensure_spooling_space()) {
    //如果开启promote跟踪,但是没有足够的空间,则尝试扩展promoInfo
    if (!expand_and_ensure_spooling_space(promoInfo)) {
      //扩展失败返回NULL
      return NULL;
    }
  }
  assert(promoInfo->has_spooling_space(), "Control point invariant");
  //内存对齐
  const size_t alloc_sz = CompactibleFreeListSpace::adjustObjectSize(word_sz);
  //从LAB中分配内存
  HeapWord* obj_ptr = ps->lab.alloc(alloc_sz);
  if (obj_ptr == NULL) {
     //分配失败,说明内存不足,尝试扩容并重新分配
     obj_ptr = expand_and_par_lab_allocate(ps, alloc_sz);
     if (obj_ptr == NULL) {
       //扩容失败返回NULL
       return NULL;
     }
  }
  //从LAB中分配内存成功
  oop obj = oop(obj_ptr);
  OrderAccess::storestore();
  //校验obj未初始化
  assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
  assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size");

  HeapWord* old_ptr = (HeapWord*)old;
  //复制对象头
  obj->set_mark(m);
  assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
  assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size");
  OrderAccess::storestore();

  if (UseCompressedClassPointers) {
    //复制klass_gap
    obj->set_klass_gap(old->klass_gap());
  }
  if (word_sz > (size_t)oopDesc::header_size()) {
    //复制对象头以外的数据,对象头就是oopDesc本身占用的空间,不包含Java对象属性
    //对象头的数据通过set_mark和set_klass就完成拷贝了
    Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(),
                                 obj_ptr + oopDesc::header_size(),
                                 word_sz - oopDesc::header_size());
  }

  if (promoInfo->tracking()) {
    //promote 跟踪
    promoInfo->track((PromotedObject*)obj, old->klass());
  }
  assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
  assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size");
  assert(old->is_oop(), "Will use and dereference old klass ptr below");

  OrderAccess::storestore();
  //设置klass
  obj->set_klass(old->klass());
  // We should now be able to calculate the right size for this object
  assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object");
  
  //执行_markBitMap和_modUnionTable打标
  collector()->promoted(true,          // parallel
                        obj_ptr, old->is_objArray(), word_sz);

  return obj;
}

bool ConcurrentMarkSweepGeneration::expand_and_ensure_spooling_space(
  PromotionInfo* promo) {
  //获取ParGCRareEvent_lock锁
  MutexLocker x(ParGCRareEvent_lock);
  //计算需要扩容的内存大小
  size_t refill_size_bytes = promo->refillSize() * HeapWordSize;
  while (true) {
    if (promo->ensure_spooling_space()) {
      //如果有充足的空间,则返回true
      assert(promo->has_spooling_space(),
             "Post-condition of successful ensure_spooling_space()");
      return true;
    }
    if (_virtual_space.uncommitted_size() < refill_size_bytes) {
     //如果老年代剩余未扩容空间不够了,返回false
      return false;
    }
    //老年代剩余空间足够,执行扩容
    expand(refill_size_bytes, MinHeapDeltaBytes,
      CMSExpansionCause::_allocate_par_spooling_space);
    //GCExpandToAllocateDelayMillis默认为0
    if (GCExpandToAllocateDelayMillis > 0) {
      os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
    }
    //进入下一次循环,直到promo由足够空间或者老年代剩余空间不够了
  }
}

HeapWord* ConcurrentMarkSweepGeneration::expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz) {
  HeapWord* res = NULL;
  MutexLocker x(ParGCRareEvent_lock);
  while (true) {
    //尝试分配,分配成功则返回
    res = ps->lab.alloc(word_sz);
    if (res != NULL) return res;
    if (_virtual_space.uncommitted_size() < (word_sz * HeapWordSize)) {
      //老年代剩余空间不足,返回NULL
      return NULL;
    }
    //老年代剩余空间充足,执行扩容
    expand(word_sz*HeapWordSize, MinHeapDeltaBytes,
      CMSExpansionCause::_allocate_par_lab);
   
    if (GCExpandToAllocateDelayMillis > 0) {
      os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
    }
  }
}

static int header_size()          { return sizeof(oopDesc)/HeapWordSize; }

void
ConcurrentMarkSweepGeneration::
par_promote_alloc_done(int thread_num) {
  CMSParGCThreadState* ps = _par_gc_thread_states[thread_num];
  //将指定线程的LAB包含的剩余的未使用的内存归还给老年代
  ps->lab.retire(thread_num);
}

bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
  size_t available = max_available();
  //历史进行promote需要的内存大小
  size_t av_promo  = (size_t)gc_stats()->avg_promoted()->padded_average();
  //如果剩余空间足够promote使用,则返回true
  bool   res = (available >= av_promo) || (available >= max_promotion_in_bytes);
  if (Verbose && PrintGCDetails) {
    gclog_or_tty->print_cr(
      "CMS: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT "),"
      "max_promo(" SIZE_FORMAT ")",
      res? "":" not", available, res? ">=":"<",
      av_promo, max_promotion_in_bytes);
  }
  return res;
}

void ConcurrentMarkSweepGeneration::promotion_failure_occurred() {
  //CMSDumpAtPromotionFailure表示在promote失败时执行dump,默认为false
  if (CMSDumpAtPromotionFailure) {
    cmsSpace()->dump_at_safepoint_with_locks(collector(), gclog_or_tty);
  }
}

GCStats* gc_stats() const { return _gc_stats; }

//返回当前可供使用的最大空间
size_t ConcurrentMarkSweepGeneration::max_available() const {
  return free() + _virtual_space.uncommitted_size();
}

inline size_t ConcurrentMarkSweepGeneration::free() const {
  return _cmsSpace->free();
}

 各方法的调用链如下:

 

4、save_marks / no_allocs_since_save_marks / oop_since_save_marks_iterate

      save_marks用于保存老年代的_saved_mark_word并开启promote 跟踪;no_allocs_since_save_marks判断老年代是否执行了promote;oop_since_save_marks_iterate是宏定义的一组方法,用于遍历promote产生的PromotedObject,包含的方法如下:

其实现如下: 

void ConcurrentMarkSweepGeneration::save_marks() {
  //设置_saved_mark_word,调用cmsSpace的_promoInfo的startTrackingPromotions方法
  cmsSpace()->save_marks();
  for (uint i = 0; i < ParallelGCThreads; i++) {
    _par_gc_thread_states[i]->promo.startTrackingPromotions();
  }
}

//判断是指执行了promote
bool ConcurrentMarkSweepGeneration::no_allocs_since_save_marks() {
  return cmsSpace()->no_allocs_since_save_marks();
}

bool CompactibleFreeListSpace::no_allocs_since_save_marks() {
  assert(_promoInfo.tracking(), "No preceding save_marks?");
  assert(SharedHeap::heap()->n_par_threads() == 0,
         "Shouldn't be called if using parallel gc.");
  return _promoInfo.noPromotions();
}

#define CMS_SINCE_SAVE_MARKS_DEFN(OopClosureType, nv_suffix)    \
                                                                \
void ConcurrentMarkSweepGeneration::                            \
oop_since_save_marks_iterate##nv_suffix(OopClosureType* cl) {   \
  cl->set_generation(this);                                     \
  //调用cmsSpace对应的遍历方法
  cmsSpace()->oop_since_save_marks_iterate##nv_suffix(cl);      \
  cl->reset_generation();                                       \
  //重置_saved_mark_word
  save_marks();                                                 \
}

ALL_SINCE_SAVE_MARKS_CLOSURES(CMS_SINCE_SAVE_MARKS_DEFN)

其调用链如下:

 5、space_iterate / oop_iterate / safe_object_iterate / object_iterate / younger_refs_iterate

      space_iterate是父类Generation的block_size,block_start,oop_iterate等方法使用的,用来遍历Generation子类包含的多个Space实例;后面三个方法都是借助父类Generation的方法实现的,不过多了一步获取freelistLock锁的动作,其实现如下:

void ConcurrentMarkSweepGeneration::space_iterate(SpaceClosure* blk, bool usedOnly) {
  //老年代只有一个Space
  blk->do_space(_cmsSpace);
}

void
ConcurrentMarkSweepGeneration::oop_iterate(ExtendedOopClosure* cl) {
  if (freelistLock()->owned_by_self()) {
    Generation::oop_iterate(cl);
  } else {
    MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag);
    Generation::oop_iterate(cl);
  }
}

void
ConcurrentMarkSweepGeneration::object_iterate(ObjectClosure* cl) {
  if (freelistLock()->owned_by_self()) {
    Generation::object_iterate(cl);
  } else {
    MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag);
    Generation::object_iterate(cl);
  }
}

void
ConcurrentMarkSweepGeneration::safe_object_iterate(ObjectClosure* cl) {
  if (freelistLock()->owned_by_self()) {
    Generation::safe_object_iterate(cl);
  } else {
    MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag);
    Generation::safe_object_iterate(cl);
  }
}

void
ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure* cl) {
  cl->set_generation(this);
  //调用父类Genaration的方法,底层调用CardTableRS::younger_refs_in_space_iterate方法完成遍历
  younger_refs_in_space_iterate(_cmsSpace, cl);
  cl->reset_generation();
}

void Generation::younger_refs_in_space_iterate(Space* sp,
                                               OopsInGenClosure* cl) {
  GenRemSet* rs = SharedHeap::heap()->rem_set();
  rs->younger_refs_in_space_iterate(sp, cl);
}

6、sample_eden_chunk

     sample_eden_chunk用来记录年轻代eden区的top属性的值,即已分配内存的边界,年轻代每次通过allocate方法成功分配内存后就会调用该方法。其实现如下:

  void sample_eden_chunk() {
    return collector()->sample_eden_chunk();
  }

  void CMSCollector::sample_eden_chunk() {
  //CMSEdenChunksRecordAlways默认为true
  if (CMSEdenChunksRecordAlways && _eden_chunk_array != NULL) {
    //获取锁_eden_chunk_lock
    if (_eden_chunk_lock->try_lock()) {
      //记录eden区top属性的值
      _eden_chunk_array[_eden_chunk_index] = *_top_addr;
      //校验top属性的值小于等于end属性的值
      assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
             "Unexpected state of Eden");
      //CMSSamplingGrain标识CMS Samples之间的最小距离,默认为16k
      //如果_eden_chunk_index等于0即第一次调用或者当前_eden_chunk_index的值比上一个大CMSSamplingGrain
      //从而在保证准确性的前提下减少_eden_chunk_array的元素个数
      if (_eden_chunk_index == 0 ||
          ((_eden_chunk_array[_eden_chunk_index] > _eden_chunk_array[_eden_chunk_index-1]) &&
           (pointer_delta(_eden_chunk_array[_eden_chunk_index],
                          _eden_chunk_array[_eden_chunk_index-1]) >= CMSSamplingGrain))) {
        //_eden_chunk_index加1,即提交一个sample   
        _eden_chunk_index++;  // commit sample
      }
      //解锁
      _eden_chunk_lock->unlock();
    }
  }
}

  其调用链如下:

7、gc_prologue / gc_epilogue

     gc_prologue是GC前调用的执行GC的准备工作,gc_epilogue是GC结束后调用的执行GC的扫尾工作,恢复部分标识到初始状态,其实现如下:

void ConcurrentMarkSweepGeneration::gc_prologue(bool full) {
  //记录GC开始前的容量和使用量
  _capacity_at_prologue = capacity();
  _used_at_prologue = used();

  collector()->gc_prologue(full);
}

inline size_t ConcurrentMarkSweepGeneration::capacity() const {
  return _cmsSpace->capacity();
}

inline size_t ConcurrentMarkSweepGeneration::used() const {
  return _cmsSpace->used();
}

void CMSCollector::gc_prologue(bool full) {
  //校验当前在安全点上
  assert(SafepointSynchronize::is_at_safepoint(), "world is stopped assumption");

  //CMSScavengeBeforeRemark表示在CMS remark前是否尝试扫描,默认为false
  //校验当前线程是VM Thread或者CMS Thread
  assert(   Thread::current()->is_VM_thread()
         || (   CMSScavengeBeforeRemark
             && Thread::current()->is_ConcurrentGC_thread()),
         "Incorrect thread type for prologue execution");

  if (_between_prologue_and_epilogue) {
    //已经调用过一次了
    return;
  }

  //将_between_prologue_and_epilogue由false改成true
  _between_prologue_and_epilogue = true;
 
  //获取锁freelistLock
  getFreelistLocks(); 
  //获取bitMapLock
  bitMapLock()->lock_without_safepoint_check();

  //是否处在标记阶段
  bool duringMarking =    _collectorState >= Marking
                         && _collectorState < Sweeping;

  //告诉年轻代记录发生修改的Klass
  if (duringMarking) {
    _ct->klass_rem_set()->set_accumulate_modified_oops(true);
  }

  bool registerClosure = duringMarking;

  ModUnionClosure* muc = CollectedHeap::use_parallel_gc_threads() ?
                                               &_modUnionClosurePar
                                               : &_modUnionClosure;                                             
  _cmsGen->gc_prologue_work(full, registerClosure, muc);

  if (!full) {
    //如果不是Full GC
    stats().record_gc0_begin();
  }
}

void CMSCollector::getFreelistLocks() const {
  _cmsGen->freelistLock()->lock_without_safepoint_check();
}

Mutex* bitMapLock()        const { return _markBitMap.lock();    }

void ConcurrentMarkSweepGeneration::gc_prologue_work(bool full,
  bool registerClosure, ModUnionClosure* modUnionClosure) {
  //校验_incremental_collection_failed属性未设置
  assert(!incremental_collection_failed(), "Shouldn't be set yet");
  assert(cmsSpace()->preconsumptionDirtyCardClosure() == NULL,
    "Should be NULL");
  if (registerClosure) {
    //这个是父类Space的属性
    cmsSpace()->setPreconsumptionDirtyCardClosure(modUnionClosure);
  }
  cmsSpace()->gc_prologue();
}

void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) {
  collector()->gc_epilogue(full);

  // Also reset promotion tracking in par gc thread states.
  if (CollectedHeap::use_parallel_gc_threads()) {
    for (uint i = 0; i < ParallelGCThreads; i++) {
      _par_gc_thread_states[i]->promo.stopTrackingPromotions(i);
    }
  }
}

void CMSCollector::gc_epilogue(bool full) {
  //校验当前在安全点上
  assert(SafepointSynchronize::is_at_safepoint(),
         "world is stopped assumption");

  //校验当前线程是VM Thread或者CMS Thread
  assert(   Thread::current()->is_VM_thread()
         || (   CMSScavengeBeforeRemark
             && Thread::current()->is_ConcurrentGC_thread()),
         "Incorrect thread type for epilogue execution");

  if (!_between_prologue_and_epilogue) {
    //_between_prologue_and_epilogue为false说明未调用prologue方法
    return;
  }
  //校验获取了锁
  assert(haveFreelistLocks(), "must have freelist locks");
  assert_lock_strong(bitMapLock());
  //将标识重置为false
  _ct->klass_rem_set()->set_accumulate_modified_oops(false);

  _cmsGen->gc_epilogue_work(full);

  if (_collectorState == AbortablePreclean || _collectorState == Precleaning) {
    //如果是这两种状态,将_start_sampling置为true
    _start_sampling = true;
  }
  //重置为0
  _eden_chunk_index = 0;
  //更新计数器
  size_t cms_used   = _cmsGen->cmsSpace()->used();
  _cmsGen->update_counters(cms_used);

  if (CMSIncrementalMode) {
    //更新_icms_start_limit和_icms_stop_limit,并将soft_end重置为_icms_start_limit
    icms_update_allocation_limits();
  }
  
  //释放锁
  bitMapLock()->unlock();
  releaseFreelistLocks();

  if (!CleanChunkPoolAsync) {
    //清理ChunkPool
    Chunk::clean_chunk_pool();
  }
  
  //did_compact和_between_prologue_and_epilogue都置为false,恢复初始状态
  set_did_compact(false);
  _between_prologue_and_epilogue = false;  // ready for next cycle
}

void ConcurrentMarkSweepGeneration::gc_epilogue_work(bool full) {
  assert(!incremental_collection_failed(), "Should have been cleared");
  cmsSpace()->setPreconsumptionDirtyCardClosure(NULL);
  cmsSpace()->gc_epilogue();

  if (PrintGC && Verbose) {
    gclog_or_tty->print(" Contiguous available " SIZE_FORMAT " bytes ",
                        contiguous_available());
  }
}

8、should_collect / should_concurrent_collect / is_too_full / collect

      should_collect用于判断是否执行垃圾回收,should_concurrent_collect用于判断当前是否应该垃圾回收,is_too_full用于判断当前老年代空间是否太满了,collect用于执行垃圾回收。其实现如下:

bool ConcurrentMarkSweepGeneration::should_collect(bool   full,
                                                   size_t size,
                                                   bool   tlab)
{
  return full || should_allocate(size, tlab); // FIX ME !!!
}

virtual bool should_allocate(size_t word_size, bool is_tlab) {
    bool result = false;
    size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize);
    if (!is_tlab || supports_tlab_allocation()) {
      result = (word_size > 0) && (word_size < overflow_limit);
    }
    return result;
  }

virtual bool supports_tlab_allocation() const { return false; }

bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const {

  assert_lock_strong(freelistLock());
  //如果已使用率大于初始使用率
  if (occupancy() > initiating_occupancy()) {
    if (PrintGCDetails && Verbose) {
      gclog_or_tty->print(" %s: collect because of occupancy %f / %f  ",
        short_name(), occupancy(), initiating_occupancy());
    }
    return true;
  }
  //UseCMSInitiatingOccupancyOnly表示是否将initiating_occupancy作为唯一指标,默认为false
  if (UseCMSInitiatingOccupancyOnly) {
    return false;
  }
  //如果扩展的原因是因为满足内存分配的需求,则返回true
  if (expansion_cause() == CMSExpansionCause::_satisfy_allocation) {
    if (PrintGCDetails && Verbose) {
      gclog_or_tty->print(" %s: collect because expanded for allocation ",
        short_name());
    }
    return true;
  }
  //如果cmsSpace应该进行垃圾收集
  if (_cmsSpace->should_concurrent_collect()) {
    if (PrintGCDetails && Verbose) {
      gclog_or_tty->print(" %s: collect because cmsSpace says so ",
        short_name());
    }
    return true;
  }
  return false;
}

 double occupancy() const { return ((double)used())/((double)capacity()); }

 double initiating_occupancy() const { return _initiating_occupancy; }

 CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; }

 bool CompactibleFreeListSpace::should_concurrent_collect() const {
  return !adaptive_freelists() && linearAllocationWouldFail();
}

bool CompactibleFreeListSpace::linearAllocationWouldFail() const {
  return _smallLinearAllocBlock._word_size == 0;
}

bool ConcurrentMarkSweepGeneration::is_too_full() const {
  bool res = should_concurrent_collect();
  //CMSIsTooFullPercentage的默认值是98,是一个阈值,超过该值认为空间太满了
  res = res && (occupancy() > (double)CMSIsTooFullPercentage/100.0);
  return res;
}

void ConcurrentMarkSweepGeneration::collect(bool   full,
                                            bool   clear_all_soft_refs,
                                            size_t size,
                                            bool   tlab)
{
  collector()->collect(full, clear_all_soft_refs, size, tlab);
}

void CMSCollector::collect(bool   full,
                           bool   clear_all_soft_refs,
                           size_t size,
                           bool   tlab)
{
  //UseCMSCollectionPassing默认为true,表示是否将GC从后台调整到前台
  if (!UseCMSCollectionPassing && _collectorState > Idling) {
    if (TraceCMSState) {
      gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " skipped full:%d CMS state %d",
        Thread::current(), full, _collectorState);
    }
    return;
  }

  if (GC_locker::is_active()) {
    //如果正在执行GC
    assert(GC_locker::needs_gc(), "Should have been set already");
    //等待GC完成后,重新计算老年代容量
    compute_new_size();
    return;
  }
  //执行GC
  acquire_control_and_collect(full, clear_all_soft_refs);
  //计数增加
  _full_gcs_since_conc_gc++;
}

其调用链如下:

9、compute_new_size / compute_new_size_free_list

      compute_new_size和compute_new_size_free_list都是GC结束后根据当前内存使用情况重新计算期望的内存容量,并做适当的扩容或者缩容处理,最大的不同是调用方不一样,其实现如下:

void ConcurrentMarkSweepGeneration::compute_new_size() {
  assert_locked_or_safepoint(Heap_lock);

  //如果增量收集失败了,扩容到最大容量
  if (incremental_collection_failed()) {
    clear_incremental_collection_failed();
    grow_to_reserved();
    return;
  }

  //根据GC后的内存使用情况计算新的内存容量,并做扩容或者缩容处理
  CardGeneration::compute_new_size();

  if (did_compact()) {
    //如果执行压缩了,则执行压缩后的重置
    cmsSpace()->reset_after_compaction();
  }
}

void ConcurrentMarkSweepGeneration::compute_new_size_free_list() {
  assert_locked_or_safepoint(Heap_lock);

  //如果增量收集失败了,扩容到最大容量
  if (incremental_collection_failed()) {
    clear_incremental_collection_failed();
    grow_to_reserved();
    return;
  }
  
  //当前空闲空间的百分比
  double free_percentage = ((double) free()) / capacity();
  double desired_free_percentage = (double) MinHeapFreeRatio / 100;
  double maximum_free_percentage = (double) MaxHeapFreeRatio / 100;

  // compute expansion delta needed for reaching desired free percentage
  if (free_percentage < desired_free_percentage) {
    //当前空闲占比小于期望的最小空闲占比,需要扩容
    size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage));
    assert(desired_capacity >= capacity(), "invalid expansion size");
    //计算扩容的内存空间
    size_t expand_bytes = MAX2(desired_capacity - capacity(), MinHeapDeltaBytes);
    if (PrintGCDetails && Verbose) {
      size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage));
      gclog_or_tty->print_cr("\nFrom compute_new_size: ");
      gclog_or_tty->print_cr("  Free fraction %f", free_percentage);
      gclog_or_tty->print_cr("  Desired free fraction %f",
        desired_free_percentage);
      gclog_or_tty->print_cr("  Maximum free fraction %f",
        maximum_free_percentage);
      gclog_or_tty->print_cr("  Capactiy " SIZE_FORMAT, capacity()/1000);
      gclog_or_tty->print_cr("  Desired capacity " SIZE_FORMAT,
        desired_capacity/1000);
      int prev_level = level() - 1;
      if (prev_level >= 0) {
        size_t prev_size = 0;
        GenCollectedHeap* gch = GenCollectedHeap::heap();
        Generation* prev_gen = gch->_gens[prev_level];
        prev_size = prev_gen->capacity();
          gclog_or_tty->print_cr("  Younger gen size " SIZE_FORMAT,
                                 prev_size/1000);
      }
      gclog_or_tty->print_cr("  unsafe_max_alloc_nogc " SIZE_FORMAT,
        unsafe_max_alloc_nogc()/1000);
      gclog_or_tty->print_cr("  contiguous available " SIZE_FORMAT,
        contiguous_available()/1000);
      gclog_or_tty->print_cr("  Expand by " SIZE_FORMAT " (bytes)",
        expand_bytes);
    }
    //执行扩容
    expand(expand_bytes, 0, CMSExpansionCause::_satisfy_free_ratio);
    if (PrintGCDetails && Verbose) {
      gclog_or_tty->print_cr("  Expanded free fraction %f",
        ((double) free()) / capacity());
    }
  } else {
    //空闲占比大于最小空闲占比,需要适当缩容
    size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage));
    assert(desired_capacity <= capacity(), "invalid expansion size");
    //计算缩容的空间
    size_t shrink_bytes = capacity() - desired_capacity;
    if (shrink_bytes >= MinHeapDeltaBytes) {
      //执行缩容
      shrink_free_list_by(shrink_bytes);
    }
  }
}

其调用链如下:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
垃圾回收器是一种自动化的内存管理机制,用于检测和回收不再使用的内存资源,以便重新分配给其他程序使用。G1(Garbage-First)垃圾回收器是Java HotSpot虚拟机中的一种垃圾回收器,下面是G1垃圾回收器的工作流程: 1. 初始标记(Initial Mark):该阶段会暂停应用程序的执行,并标记所有根对象直接引用的对象。这个过程很快,因为只标记那些直接与根对象相关的对象。 2. 并发标记(Concurrent Mark):在此阶段,应用程序和垃圾回收线程并发执行。垃圾回收线程标记从根对象开始,遍历整个对象图,并标记所有可达的对象。这个阶段可能会在应用程序运行时进行,并且不会停止应用程序的执行。 3. 最终标记(Final Mark):在并发标记阶段结束后,将再次暂停应用程序的执行,并完成剩余的标记工作。这个阶段主要标记在并发标记阶段还在使用但后续已不再使用的对象。 4. 筛选回收(Live Data Counting and Evacuation):G1会根据各个区域中存活数据的数量来设置优先级,并优先回收垃圾最多的区域。在筛选回收阶段,G1将未被引用的对象清理出堆空间,并将存活的对象复制到空闲的区域中。 5. 内存整理(Compaction):G1会对整个堆进行内存整理,目的是减少内存碎片化,提高内存利用率。在内存整理过程中,G1会将存活对象从一个或多个区域复制到一个连续的空闲区域。 总体来说,G1垃圾回收器通过标记、清理和整理的方式,有效地管理内存并进行垃圾回收。它具有可预测的停顿时间和高效的内存整理能力,适用于大型应用程序和需要更低停顿时间的场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值