First, determine whether GC will be performed based on the status of the DisableExplicitGC JVM startup parameter. If GC is required, different GCS will handle GC differently.

1. G1 GC processing

If it is a System. The gc () trigger gc, G1 gc could decide according to ExplicitGCInvokesConcurrent the JVM parameter is the default gc (lightweight gc, YoungGC) or FullGC.

Reference code g1Collectedheap.cpp:

// Should parallel GC, i.e., lighter GC, be used for GCCause:: _javA_lang_system_GC, Here is whether the JVM ExplicitGCInvokesConcurrent to true if (should_do_concurrent_full_gc (cause)) {return try_collect_concurrently(cause, gc_count_before, old_marking_started_before); } else {// otherwise enter full GC VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause); VMThread::execute(&op); return op.gc_succeeded(); }Copy the code

2. ZGC treatment

The System. Gc () trigger is not supported.

Reference source: zdriver.cpp

Void ZDriver::collect(GCCause::Cause Cause) {switch (Cause) { Case GCCause:: _wb_young_GC: Case GCCause::_wb_conc_mark: case GCCause:: _wb_full_GC: case GCCause::_dcmd_gc_run: case GCCause::_java_lang_system_gc: case GCCause::_full_gc_alot: case GCCause::_scavenge_alot: case GCCause::_jvmti_force_gc: case GCCause::_metadata_GC_clear_soft_refs: // Start synchronous GC _gc_cycle_port.send_sync(cause); break; case GCCause::_z_timer: case GCCause::_z_warmup: case GCCause::_z_allocation_rate: case GCCause::_z_allocation_stall: case GCCause::_z_proactive: case GCCause::_z_high_usage: case GCCause::_metadata_GC_threshold: // Start asynchronous GC _gc_cycle_port.send_async(cause); break; case GCCause::_gc_locker: // Restart VM operation previously blocked by the GC locker _gc_locker_port.signal(); break; case GCCause::_wb_breakpoint: ZBreakpoint::start_gc(); _gc_cycle_port.send_async(cause); break; // For other reasons, if GC is not triggered, GCCause:: _javA_lang_system_gc will go to this default: // Other causes not supported fatal("Unsupported GC cause (%s)", GCCause::to_string(cause)); break; }}Copy the code

3. Shenandoah GC processing

Shenandoah is handled in a similar way to the G1 GC. The JVM parameter DisableExplicitGC is used to determine whether a GC is allowed. Because the outer JVM_ENTRY_NO_ENV(void, JVM_GC(void)) already handles this state bit. If so, request GC and block until the GC request is processed. Then according to ExplicitGCInvokesConcurrent the JVM parameter is the default GC (parallel GC, lightweight YoungGC) or FullGC.

Reference source shenandoahControlThread. CPP

void ShenandoahControlThread::request_gc(GCCause::Cause cause) { assert(GCCause::is_user_requested_gc(cause) || GCCause::is_serviceability_requested_gc(cause) || cause == GCCause::_metadata_GC_clear_soft_refs || cause == GCCause::_full_gc_alot || cause == GCCause::_wb_full_gc || cause == GCCause::_scavenge_alot, "only requested GCs here");  GCCause:: _dcmD_gc_run, GCCause:: _jVMti_force_GC, GCCause::_heap_inspection, GCCause:: _jvmti_force_GC GCCause::_heap_dump either) if (is_explicit_gc(cause)) {// DisableExplicitGC is false if (! DisableExplicitGC) {// Request GC handle_requested_GC (cause); } } else { handle_requested_gc(cause); }}Copy the code

The code flow for requesting GC is as follows:

void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { MonitorLocker ml(&_gc_waiters_lock); Size_t current_gc_id = get_gc_id(); // For GC, set id + 1 size_t required_gc_id = current_gc_id + 1; While (current_gc_id < required_gc_id) {// While (current_gc_id < required_gc_id) {// While (current_gc_id < required_gc_id) {// While (current_gc_request.set (); GCCause:: _javA_lang_system_gc _requested_gc_cause = cause; GCCause::_java_lang_system_gc; // Wait for the notify gc lock to be executed and complete ml.wait(); current_gc_id = get_gc_id(); }}Copy the code

For GCCause:: _JAVA_lang_system_GC, the GC flow looks like this:

bool explicit_gc_requested = _gc_requested.is_set() && is_explicit_gc(_requested_gc_cause); Else if (explicit_gc_requested) {cause = _requested_gc_cause; log_info(gc)("Trigger: Explicit GC request (%s)", GCCause::to_string(cause)); heuristics->record_requested_gc(); / / if the JVM parameter ExplicitGCInvokesConcurrent is true, Is the default light GC if (ExplicitGCInvokesConcurrent) {policy - > record_explicit_to_concurrent (); mode = default_mode; // Unload and clean up everything heap->set_unload_classes(heuristics->can_unload_classes()); } else {// otherwise, execute FullGC policy->record_explicit_to_full(); mode = stw_full; }}Copy the code