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; }
其调用链如下:
![](https://img.haomeiwen.com/i26273155/31d66ce059da0159.png)
![](https://img.haomeiwen.com/i26273155/63170d17bc437bc0.png)
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;
}
其调用链如下:
![](https://img.haomeiwen.com/i26273155/d1a2472a1f7a115a.png)
![](https://img.haomeiwen.com/i26273155/e282df26e57a99d3.png)
![](https://img.haomeiwen.com/i26273155/8200f0ca7780d569.png)
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();
}
各方法的调用链如下:
![](https://img.haomeiwen.com/i26273155/401845981c2c2d0c.png)
![](https://img.haomeiwen.com/i26273155/f3f40fe3ba2a12ff.png)
![](https://img.haomeiwen.com/i26273155/82b4a26f1af78766.png)
![](https://img.haomeiwen.com/i26273155/5aa240d341538fc0.png)
![](https://img.haomeiwen.com/i26273155/6bfae2559099c136.png)
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,包含的方法如下:
![](https://img.haomeiwen.com/i26273155/46db2523c582f76a.png)
其实现如下:
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)
其调用链如下:
![](https://img.haomeiwen.com/i26273155/9d7c751c51dab3cd.png)
![](https://img.haomeiwen.com/i26273155/efd885b3e01f53e3.png)
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();
}
}
}
其调用链如下:
![](https://img.haomeiwen.com/i26273155/0188a882721d4572.png)
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++;
}
其调用链如下:
![](https://img.haomeiwen.com/i26273155/01949cd4a7d55bd1.png)
![](https://img.haomeiwen.com/i26273155/e00d085cfdc83b9d.png)
![](https://img.haomeiwen.com/i26273155/34dbe002ab40c971.png)
![](https://img.haomeiwen.com/i26273155/2b29aa73bac2bd6d.png)
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);
}
}
}
其调用链如下:
![](https://img.haomeiwen.com/i26273155/798d66c697317873.png)
![](https://img.haomeiwen.com/i26273155/b0c0377b686a842a.png)
网友评论