在initialize_heap_sizes中初始化了gc的線程,后續(xù)的gc以任務(wù)的形式提交
主要有三種:
1.觸發(fā)gc操作一般在分配內(nèi)存時(shí),空間不足可能要oom時(shí)才尋找合適的stw時(shí)機(jī)
(某面試官說(shuō)道:有人的地方就有江湖,有分配內(nèi)存的地方都可能oom)
2.system.gc()
3.定時(shí)任務(wù)G1PeriodicGCTask
想看gc方法找gcRoots什么的需要一個(gè)切入點(diǎn),定時(shí)任務(wù)作為一個(gè)保底的觸發(fā)機(jī)制,可以不斷嘗試觸發(fā)gc
先看簡(jiǎn)單的定時(shí)任務(wù)
void G1PeriodicGCTask::execute() {
check_for_periodic_gc();
// G1PeriodicGCInterval is a manageable flag and can be updated
// during runtime. If no value is set, wait a second and run it
// again to see if the value has been updated. Otherwise use the
// real value provided.
//這個(gè)意思就是如果后續(xù)運(yùn)行過(guò)程中進(jìn)行了參數(shù)調(diào)整,可以實(shí)時(shí)調(diào)整
schedule(G1PeriodicGCInterval == 0 ? 1000 : G1PeriodicGCInterval);
}
void ConcurrentGCThread::run() {
// Setup handle area
set_active_handles(JNIHandleBlock::allocate_block());
// Wait for initialization to complete
wait_init_completed();
run_service();
// Signal thread has terminated
MonitorLocker ml(Terminator_lock);
Atomic::release_store(&_has_terminated, true);
ml.notify_all();
}
定時(shí)任務(wù)提交給了G1ServiceThread,這個(gè)類繼承到最上面是一個(gè)javaThread,和java一樣看run方法就行,最后調(diào)用到了task中的execute,
在執(zhí)行check_for_periodic_gc()完成后設(shè)置下一次的定時(shí)任務(wù)
void G1PeriodicGCTask::check_for_periodic_gc() {
// If disabled, just return.
// 間隔設(shè)置成0后將不會(huì)執(zhí)行g(shù)c,直接開(kāi)啟下一秒的gc任務(wù)
if (G1PeriodicGCInterval == 0) {
return;
}
//try_collect就是檢查過(guò)程,真的要gc的話看里面
log_debug(gc, periodic)("Checking for periodic GC.");
if (should_start_periodic_gc()) {
if (!G1CollectedHeap::heap()->try_collect(GCCause::_g1_periodic_collection)) {
log_debug(gc, periodic)("GC request denied. Skipping.");
}
}
}
這里的GCCause::_g1_periodic_collection為25
bool G1CollectedHeap::try_collect(GCCause::Cause cause) {
//堆鎖判斷是否是當(dāng)前線程的鎖
assert_heap_not_locked();
// Lock to get consistent set of values.
uint gc_count_before;
uint full_gc_count_before;
uint old_marking_started_before;
{
MutexLocker ml(Heap_lock);
gc_count_before = total_collections();
full_gc_count_before = total_full_collections();
old_marking_started_before = _old_marking_cycles_started;
}
//判斷是否觸發(fā)并發(fā)的full gc
if (should_do_concurrent_full_gc(cause)) {
return try_collect_concurrently(cause,
gc_count_before,
old_marking_started_before);
} else if (GCLocker::should_discard(cause, gc_count_before)) {
//判斷是否是初始化gc并且獲取的gc次數(shù)被修改過(guò)
// Indicate failure to be consistent with VMOp failure due to
// another collection slipping in after our gc_count but before
// our request is processed.
return false;
} else if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc
DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) {
//白盒子測(cè)試或者初始化
// Schedule a standard evacuation pause. We're setting word_size
// to 0 which means that we are not requesting a post-GC allocation.
VM_G1CollectForAllocation op(0, /* word_size */
gc_count_before,
cause,
policy()->max_pause_time_ms());
VMThread::execute(&op);
return op.gc_succeeded();
} else {
// Schedule a Full GC.
//簡(jiǎn)單的full gc
VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause);
VMThread::execute(&op);
return op.gc_succeeded();
}
}
gc有多少種cause可以查看GCCause.cpp
case _java_lang_system_gc:
return "System.gc()";
case _full_gc_alot:
return "FullGCAlot";
case _scavenge_alot:
return "ScavengeAlot";
case _allocation_profiler:
return "Allocation Profiler";
case _jvmti_force_gc:
return "JvmtiEnv ForceGarbageCollection";
case _gc_locker:
return "GCLocker Initiated GC";
case _heap_inspection:
return "Heap Inspection Initiated GC";
case _heap_dump:
return "Heap Dump Initiated GC";
//...省略
case _g1_inc_collection_pause:
return "G1 Evacuation Pause";
通過(guò)這個(gè)參數(shù)可以統(tǒng)計(jì)出整個(gè)jvm已經(jīng)進(jìn)行的gc類型,比如jstat -gccause <pid> 100 (意思是每秒打印gc信息)
其中有一個(gè)字段LGCC對(duì)應(yīng)這個(gè)原因
C:\Users\tango>jstat -gccause 21136 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT LGCC GCC
0.00 97.40 10.99 64.32 99.07 95.76 54 0.921 0 0.000 6 0.013 0.934 G1 Evacuation Pause No GC
0.00 97.40 10.99 64.32 99.07 95.76 54 0.921 0 0.000 6 0.013 0.934 G1 Evacuation Pause No GC
0.00 97.40 10.99 64.32 99.07 95.76 54 0.921 0 0.000 6 0.013 0.934 G1 Evacuation Pause No GC
0.00 97.40 10.99 64.32 99.07 95.76 54 0.921 0 0.000 6 0.013 0.934 G1 Evacuation Pause No GC
jvm內(nèi)存觸發(fā)
結(jié)合前面內(nèi)存分配的過(guò)程就能快速找到
tlab觸發(fā)##
開(kāi)啟tlab后,如果內(nèi)存不夠走tlab_slow分配會(huì)調(diào)用這里,注意這里需要分配的東西是tlab的空間,與后續(xù)heap直接分配的方法一樣但是對(duì)象不一樣
HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size,
size_t requested_size,
size_t* actual_size) {
//safepoint就是安全點(diǎn),jvm線程執(zhí)行字節(jié)碼自己能夠知道
assert_heap_not_locked_and_not_at_safepoint();
//大對(duì)象直接走的heap,tlab不走
assert(!is_humongous(requested_size), "we do not allow humongous TLABs");
return attempt_allocation(min_size, requested_size, actual_size);
}
attempt_allocation和heap觸發(fā)的一樣
heap觸發(fā)##
HeapWord* MemAllocator::allocate_outside_tlab(Allocation& allocation) const {
allocation._allocated_outside_tlab = true;
HeapWord* mem = Universe::heap()->mem_allocate(_word_size, &allocation._overhead_limit_exceeded);
if (mem == NULL) {
return mem;
}
NOT_PRODUCT(Universe::heap()->check_for_non_bad_heap_word_value(mem, _word_size));
size_t size_in_bytes = _word_size * HeapWordSize;
_thread->incr_allocated_bytes(size_in_bytes);
return mem;
}
mem_allocate
HeapWord*
G1CollectedHeap::mem_allocate(size_t word_size,
bool* gc_overhead_limit_was_exceeded) {
assert_heap_not_locked_and_not_at_safepoint();
if (is_humongous(word_size)) {
return attempt_allocation_humongous(word_size);
}
size_t dummy = 0;
//和tlab_slow一個(gè)方法
return attempt_allocation(word_size, word_size, &dummy);
}
attempt_allocation_humongous
里面可以觸發(fā)gc原因的有
_g1_humongous_allocation
_g1_preventive_collection
特別注意大對(duì)象觸發(fā)時(shí),由于大對(duì)象消耗內(nèi)存很快,所以會(huì)觸發(fā)檢查是否要進(jìn)行并發(fā)標(biāo)記
// Humongous objects can exhaust the heap quickly, so we should check if we
// need to start a marking cycle at each humongous object allocation. We do
// the check before we do the actual allocation. The reason for doing it
// before the allocation is that we avoid having to keep track of the newly
// allocated memory while we do a GC.
if (policy()->need_to_start_conc_mark("concurrent humongous allocation",
word_size)) {
collect(GCCause::_g1_humongous_allocation);
}
attempt_allocation
inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
assert_heap_not_locked_and_not_at_safepoint();
assert(!is_humongous(desired_word_size), "attempt_allocation() should not "
"be called for humongous allocation requests");
//numa從系統(tǒng)的多線程空間獲取內(nèi)存
HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size);
//numa分配失敗
if (result == NULL) {
*actual_word_size = desired_word_size;
//內(nèi)部可能觸發(fā)gc再進(jìn)行內(nèi)存分配
result = attempt_allocation_slow(desired_word_size);
}
assert_heap_not_locked();
if (result != NULL) {
assert(*actual_word_size != 0, "Actual size must have been set here");
dirty_young_block(result, *actual_word_size);
} else {
*actual_word_size = 0;
}
return result;
}
system.gc()
JVM_ENTRY_NO_ENV(void, JVM_GC(void))
if (!DisableExplicitGC) {
EventSystemGC event;
event.set_invokedConcurrent(ExplicitGCInvokesConcurrent);
Universe::heap()->collect(GCCause::_java_lang_system_gc);
event.commit();
}
JVM_END
//collect
void G1CollectedHeap::collect(GCCause::Cause cause) {
try_collect(cause);
}
回到了開(kāi)始的定時(shí)任務(wù),而且人家還是一秒一次的
如果版本支持G1PeriodicGCTask這個(gè)system.gc()就不要寫了吧