不想每次都是背八股文,干脆直接看源码
concurrentMarkSweepGeneration.hpp文件
bool isMarked(HeapWord* addr) const;
bool par_isMarked(HeapWord* addr) const; // do not lock checks
bool isUnmarked(HeapWord* addr) const;
上面这些应该是用来标记内存的
HeapWord指针,用来指向堆内存地址addr
cms的bitmap,位图,猜测是标记内存对象存活还是应该回收:
class CMSBitMap VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
HeapWord* _bmStartWord; // base address of range covered by map
size_t _bmWordSize; // map size (in #HeapWords covered)
const int _shifter; // shifts to convert HeapWord to bit position
VirtualSpace _virtual_space; // underlying the bit map
BitMap _bm; // the bit map itself
public:
Mutex* const _lock; // mutex protecting _bm;
public:
收集器的状态:
public:
enum CollectorState { 收集器状态
Resizing = 0,
Resetting = 1,
Idling = 2,
InitialMarking = 3, 初始标记
Marking = 4,
Precleaning = 5,
AbortablePreclean = 6,
FinalMarking = 7, 最终标记
Sweeping = 8 清除
};
这个方法看不太懂
public:
CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
CardTableRS* ct,
ConcurrentMarkSweepPolicy* cp);
ConcurrentMarkSweepThread* cmsThread() { return _cmsThread; }
hpp文件主要是一些函数的声明,PushAndMarkClosure,这种跟遍历survivor有关,暂时看不懂
concurrentMarkSweepGeneration.cpp文件
初始化年代计数器
void ConcurrentMarkSweepGeneration::initialize_performance_counters() {
const char* gen_name = "old";
// Generation Counters - generation 1, 1 subspace
_gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
_space_counters = new GSpaceCounters(gen_name, 0,
_virtual_space.reserved_size(),
this, _gen_counters);
}
Collector的一些参数:
CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
CardTableRS* ct,
ConcurrentMarkSweepPolicy* cp):
_cmsGen(cmsGen),
_ct(ct),
_ref_processor(NULL), // will be set later
_conc_workers(NULL), // may be set later
_abort_preclean(false),
_start_sampling(false),
_between_prologue_and_epilogue(false),
_markBitMap(0, Mutex::leaf + 1, "CMS_markBitMap_lock"),
_modUnionTable((CardTableModRefBS::card_shift - LogHeapWordSize),
-1 /* lock-free */, "No_lock" /* dummy */),
_modUnionClosure(&_modUnionTable),
_modUnionClosurePar(&_modUnionTable),
// Adjust my span to cover old (cms) gen
_span(cmsGen->reserved()),
// Construct the is_alive_closure with _span & markBitMap
_is_alive_closure(_span, &_markBitMap),
_restart_addr(NULL),
_overflow_list(NULL),
_stats(cmsGen),
_eden_chunk_lock(new Mutex(Mutex::leaf + 1, "CMS_eden_chunk_lock", true)),
_eden_chunk_array(NULL), // may be set in ctor body
_eden_chunk_capacity(0), // -- ditto --
_eden_chunk_index(0), // -- ditto --
_survivor_plab_array(NULL), // -- ditto --
_survivor_chunk_array(NULL), // -- ditto --
_survivor_chunk_capacity(0), // -- ditto --
_survivor_chunk_index(0), // -- ditto --
_ser_pmc_preclean_ovflw(0),
_ser_kac_preclean_ovflw(0),
_ser_pmc_remark_ovflw(0),
_par_pmc_remark_ovflw(0),
_ser_kac_ovflw(0),
_par_kac_ovflw(0),
空间计数器和年代计数器叠加:
void ConcurrentMarkSweepGeneration::update_counters() {
if (UsePerfData) {
_space_counters->update_all();
_gen_counters->update_all();
}
}
HeapWordSize 应该是一个heapword的块大小
Verbose 中文意思冗长的,是一个VM Option的配置参数,比如-verbose:class,就会打印出加载的类信息
freeList jvm中空闲内存块存在freeList中,需要时分配freeList中的一块给某线程
新生代提升到老年代
oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) {
assert(obj_size == (size_t)obj->size(), "bad obj_size passed in");
// allocate, copy and if necessary update promoinfo --
// delegate to underlying space.
assert_lock_strong(freelistLock());
#ifndef PRODUCT
if (Universe::heap()->promotion_should_fail()) {
return NULL;
}
#endif // #ifndef PRODUCT
oop res = _cmsSpace->promote(obj, obj_size);
if (res == NULL) { 如果提升到老年代失败,说明老年代空间不足
// expand and retry
size_t s = _cmsSpace->expansionSpaceRequired(obj_size); // HeapWords
expand(s*HeapWordSize, MinHeapDeltaBytes,
CMSExpansionCause::_satisfy_promotion); 老年代扩容
// Since there's currently no next generation, we don't try to promote
// into a more senior generation.
assert(next_gen() == NULL, "assumption, based upon which no attempt "
"is made to pass on a possibly failing "
"promotion to next generation");
res = _cmsSpace->promote(obj, obj_size); 再次尝试扩容
}
minor gc到达指定次数,进行full gc
void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
unsigned int gc_count = gch->total_full_collections();
if (gc_count == full_gc_count) {
MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag);
_full_gc_requested = true;
_full_gc_cause = cause;
CGC_lock->notify(); // nudge CMS thread
} else {
assert(gc_count > full_gc_count, "Error: causal loop");
}
}
CMS GC 共分为 Background 和 Foreground 两种模式,前者就是我们常规理解中的并发收集,可以不影响正常的业务线程运行,但 Foreground Collector 却有很大的差异,他会进行一次压缩式 GC。
Compaction 压缩,所以为啥要压缩
做标记清除
void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
CollectorState first_state, bool should_start_over) {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Pass concurrent collection to foreground "
"collector with count %d",
_full_gcs_since_conc_gc);
}
switch (_collectorState) {
case Idling:
if (first_state == Idling || should_start_over) {
// The background GC was not active, or should
// restarted from scratch; start the cycle.
_collectorState = InitialMarking;
}
// If first_state was not Idling, then a background GC
// was in progress and has now finished. No need to do it
// again. Leave the state as Idling.
break;
case Precleaning:
// In the foreground case don't do the precleaning since
// it is not done concurrently and there is extra work
// required.
_collectorState = FinalMarking;
}
#foreground模式进行收集
collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause());
// For a mark-sweep, compute_new_size() will be called
// in the heap's do_collection() method.
}
UseAdaptiveSizePolicy: 如果开启 AdaptiveSizePolicy,则每次 GC 后会重新计算 Eden、From 和 To 区的大小,计算依据是 GC 过程中统计的 GC 时间、吞吐量、内存占用量。
ConcurrentMarkSweepThread 这是个啥?
gc_prologue
klass 又是个啥?
bool CMSCollector::have_cms_token() 是个啥又
class VerifyMarkedClosure: public BitMapClosure {
CMSBitMap* _marks;
bool _failed;
update_should_unload_classes 如果old区内存太满,则卸载类
TLAB又是个啥
Thread Local Allocation Buffer,每个线程都有一个TLAB,所有的TLAB存在alloc_buffers[thread_count]这个buffer里面。
其实还有PLAB( promotion local allocation buffer)。每一个线程在survival space和old space中都一个PLAB。在提升的时候,可以避免多线程的竞争,从而提升效率。
更新容量以及年代计数器
bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) {
assert_locked_or_safepoint(Heap_lock);
bool result = _virtual_space.expand_by(bytes);
if (result) {
size_t new_word_size =
heap_word_size(_virtual_space.committed_size());
增长容量到指定大小
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);
DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
}
return success;
}
tenuredGeneration.cpp(看完)
bool TenuredGeneration::should_collect(bool full,
size_t size,
bool is_tlab)
是否该收集,在空间不足,或者新年代晋升得到老年代内存不足时,进行收集
收集:
void TenuredGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
retire_alloc_buffers_before_full_gc();
OneContigSpaceCardGeneration::collect(full, clear_all_soft_refs,
size, is_tlab);
}
而OneContigSpaceCardGeneration的collect定义在tenuredGeneration.hpp文件:
class TenuredGeneration: public OneContigSpaceCardGeneration {
friend class VMStructs;
protected:
#if INCLUDE_ALL_GCS
// To support parallel promotion: an array of parallel allocation
// buffers, one per thread, initially NULL.
ParGCAllocBufferWithBOT** _alloc_buffers;
#endif // INCLUDE_ALL_GCS
// Retire all alloc buffers before a full GC, so that they will be
// re-allocated at the start of the next young GC.
void retire_alloc_buffers_before_full_gc();
GenerationCounters* _gen_counters;
CSpaceCounters* _space_counters;
par_promote,是promote的多线程版,完成新生代到老年代的提升
oop TenuredGeneration::par_promote(int thread_num,
oop old, markOop m, size_t word_sz) {
其中markOOP就是传说中的mark word
parNewGeneration.cpp
overflow_stack,感觉是线程的栈
void ParScanThreadState::push_on_overflow_stack(oop p) {
assert(ParGCUseLocalOverflow, "Else should not call");
overflow_stack()->push(p);
assert(young_gen()->overflow_list() == NULL, "Error");
}
adjoiningGenerations.hpp
这个主要是定义young_gen和old_gen的
class AdjoiningGenerations : public CHeapObj<mtGC> {
friend class VMStructs;
private:
// The young generation and old generation, respectively
PSYoungGen* _young_gen;
PSOldGen* _old_gen;
// The spaces used by the two generations.
AdjoiningVirtualSpaces _virtual_spaces;
psYoungGen.hpp
传说中的_eden区,from 区和to区
class PSYoungGen : public CHeapObj<mtGC> {
friend class VMStructs;
friend class ParallelScavengeHeap;
friend class AdjoiningGenerations;
protected:
MemRegion _reserved;
PSVirtualSpace* _virtual_space;
// Spaces
MutableSpace* _eden_space;
MutableSpace* _from_space;
MutableSpace* _to_space;
psYoungGen.cpp
为eden space和from space,to space分配内存空间,注意有个alignment,也就是分配的空间都是对齐的
void PSYoungGen::initialize_work() {
_reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(),
(HeapWord*)virtual_space()->high_boundary());
MemRegion cmr((HeapWord*)virtual_space()->low(),
(HeapWord*)virtual_space()->high());
Universe::heap()->barrier_set()->resize_covered_region(cmr);
if (ZapUnusedHeapArea) {
// Mangle newly committed space immediately because it
// can be done here more simply that after the new
// spaces have been computed.
SpaceMangler::mangle_region(cmr);
}
if (UseNUMA) {
_eden_space = new MutableNUMASpace(virtual_space()->alignment());
} else {
_eden_space = new MutableSpace(virtual_space()->alignment());
}
_from_space = new MutableSpace(virtual_space()->alignment());
_to_space = new MutableSpace(virtual_space()->alignment());
...
_eden_mark_sweep =
new PSMarkSweepDecorator(_eden_space, NULL, MarkSweepDeadRatio);
...
_gen_counters = new PSGenerationCounters("new", 0, 3, _virtual_space);
其中new代表新生代, 0是代数,3是spaces
_eden_counters = new SpaceCounters("eden", 0, max_eden_size, _eden_space,
_gen_counters);
_from_counters = new SpaceCounters("s0", 1, max_survivor_size, _from_space,
_gen_counters);
_to_counters = new SpaceCounters("s1", 2, max_survivor_size, _to_space,
_gen_counters);
这就是传说中的s0,s1,eden,对应的内存计数器
然后看eden,from,to的地址分配,可知他们是首尾相连的
void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) {
assert(eden_size < virtual_space()->committed_size(), "just checking");
assert(eden_size > 0 && survivor_size > 0, "just checking");
// Initial layout is Eden, to, from. After swapping survivor spaces,
// that leaves us with Eden, from, to, which is step one in our two
// step resize-with-live-data procedure.
char *eden_start = virtual_space()->low();
char *to_start = eden_start + eden_size;
char *from_start = to_start + survivor_size;
char *from_end = from_start + survivor_size;
下面有MemRegion的分配:
MemRegion eden_mr((HeapWord*)eden_start, (HeapWord*)to_start);
MemRegion to_mr ((HeapWord*)to_start, (HeapWord*)from_start);
MemRegion from_mr((HeapWord*)from_start, (HeapWord*)from_end);
PSMarkSweepDecorator 又是个啥,wocao
对young区的大小进行重新调整,可能是expand,也可能shrink:
bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
const size_t alignment = virtual_space()->alignment();
size_t orig_size = virtual_space()->committed_size();
bool size_changed = false;
// There used to be this guarantee there.
// guarantee ((eden_size + 2*survivor_size) <= _max_gen_size, "incorrect input arguments");
// Code below forces this requirement. In addition the desired eden
// size and disired survivor sizes are desired goals and may
// exceed the total generation size.
assert(min_gen_size() <= orig_size && orig_size <= max_size(), "just checking");
// Adjust new generation size
const size_t eden_plus_survivors =
align_size_up(eden_size + 2 * survivor_size, alignment);
size_t desired_size = MAX2(MIN2(eden_plus_survivors, max_size()),
交换from和to,不过from_mark_sweep又是啥?
void PSYoungGen::swap_spaces() {
MutableSpace* s = from_space();
_from_space = to_space();
_to_space = s;
// Now update the decorators.
PSMarkSweepDecorator* md = from_mark_sweep();
_from_mark_sweep = to_mark_sweep();
_to_mark_sweep = md;
assert(from_mark_sweep()->space() == from_space(), "Sanity");
assert(to_mark_sweep()->space() == to_space(), "Sanity");
}
所谓mangle实际就是把未使用的内存区域填充为一个特定的值:
// Simply mangle the MemRegion mr.
void SpaceMangler::mangle_region(MemRegion mr) {
assert(ZapUnusedHeapArea, "Mangling should not be in use");
#ifdef ASSERT
if(TraceZapUnusedHeapArea) {
gclog_or_tty->print("Mangling [0x%x to 0x%x)", mr.start(), mr.end());
}
Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord);
if(TraceZapUnusedHeapArea) {
gclog_or_tty->print_cr(" done");
}
#endif
}
上述代码的Copy::fill_to_words其实调用了:
static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
#ifdef _LP64
julong* to = (julong*) tohw;
julong v = ((julong) value << 32) | value;
#else
juint* to = (juint*) tohw;
juint v = value;
#endif // _LP64
while (count-- > 0) {
*to++ = v;
}
也就是按序,把内存每个变量赋值为指定value
const juint badHeapWordVal = 0xBAADBABE;
const juint max_juint = (juint)-1; // 0xFFFFFFFF largest juint
psVirtualspace.hpp
inline void PSVirtualSpace::set_reserved(ReservedSpace rs) {
set_reserved(rs.base(), rs.base() + rs.size(), rs.special());
}
inline void PSVirtualSpace::set_committed(char* low_addr, char* high_addr) {
_committed_low_addr = low_addr;
_committed_high_addr = high_addr;
}
reserved
reserved memory 是指JVM 通过mmaped PROT_NONE 申请的虚拟地址空间,在页表中已经存在了记录(entries),其实就是reserved(预定)的大小
在堆内存下,就是xmx值,jvm申请的最大保留内存。
committed
committed memory 是JVM向操做系统实际分配的内存(malloc/mmap),mmaped PROT_READ | PROT_WRITE,相当于程序实际申请的可用内存。
在堆内存下,当xms没有扩容时就是xms值,最小堆内存,扩容后就是扩容后的值,heap committed memory,。
注意,committed申请的内存并不是说直接占用了物理内存,由于操作系统的内存管理是惰性的,对于已申请的内存虽然会分配地址空间,但并不会直接占用物理内存,真正使用的时候才会映射到实际的物理内存。
uncommited
reserved = committed + uncommitted
psVirtualspace.cpp
这个类应该是用来分配页表(虚拟空间的),下面的代码释放内存:
void PSVirtualSpace::release() {
DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
// This may not release memory it didn't reserve.
// Use rs.release() to release the underlying memory instead.
_reserved_low_addr = _reserved_high_addr = NULL;
_committed_low_addr = _committed_high_addr = NULL;
_special = false;
}
下面的expand_by,表示内存的扩容,其实是增加commited memory,shirink_by也是减少commited memory
bool PSVirtualSpace::expand_by(size_t bytes) {
assert(is_aligned(bytes), "arg not aligned");
DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
if (uncommitted_size() < bytes) {
return false;
}
char* const base_addr = committed_high_addr();
bool result = special() ||
os::commit_memory(base_addr, bytes, alignment(), !ExecMem);
if (result) {
_committed_high_addr += bytes;
}
return result;
}
其中 os::commit_memory(base_addr, bytes, alignment(), !ExecMem); 用来向操作系统请求分配内存,uncommit_memory在shrink_by调用,用来通知操作系统释放内存