目录
2、allocate / par_allocate / expand_and_allocate /allocation_limit_reached
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
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 "%%)",