Full GC

G1 is designed to avoid Full GC (FGC), but there are always special cases where G1 needs to start a fallback for FGC if the current rate of concurrent collection is not keeping up with the rate of object allocation. In order to take full advantage of the multi-core processor, JEP 307 proposed a multi-threaded tag collation algorithm for G1 FGC. The number of threads in the multi-threaded FGC can be controlled by -xx :ParallelGCThreads.

G1’s multithreaded FGC is a global STW process similar to the FGC of Parallel GC. G1 uses thread groups for garbage collection and does not allow Mutator threads to run at all stages. The implementation of FGC is located at G1FullCollector:: Collect (), as shown in Listing 11-7:

Listing 11-7 G1 FGC

void G1FullCollector::collect() {phase1_mark_live_objects(); phase2_prepare_compaction(); phase3_adjust_pointers(); phase4_do_compaction(); }Copy the code

As mentioned earlier, FGC is a standard mark-up algorithm that submits tasks to a thread pool at each step, using multiple threads to complete the task, minimizing STW time. There are many scenarios in which FGC can be triggered, for example:

Mixed GC triggers FGC if the rate of old generation collection is less than the rate of object allocation or promotion.

YGC finally moves the living object to another partition. If there is no Region that can hold the living object, FGC is triggered.

FGC is triggered if there are not enough regions to hold Humongous objects.

Application calls to System.gc() also trigger FGC.

Because of the global STW nature of FGC, frequent FGC occurrences are a bad sign, indicating that the application’s features do not fit well with the current G1 parameter configuration, requiring the developer to identify problems and further tune them.

String deduplication

If readers a Heap Dump on the virtual machine (XX: + HeapDumpOnOutOfMemoryError or jmap trigger) operation, observe the Java Heap accounted for the largest is usually some byte [] objects, these byte [] objects are often members of the String, That is, string objects are a huge part of the Java heap, and if you can find duplicate strings and eliminate them, you can save a lot of memory. You can manually call String.intern() to eliminate duplicate strings, but this requires the developer to know which strings are likely to duplicate, or you can use G1’s new feature to do this automatically.

Both YGC and FGC in G1 can trigger string deduplication by enabling -xx :+UseStringDeduplication. If the automatic de-duplication option is found to be enabled during YGC’s copy_to_survivor() procedure, G1 calls G1StringDedup::enqueue_from_evacuation() to automatically discover strings that can be de-duplicated, as shown in Listing 11-8:

Listing 11-8 selects the repeated string

bool G1StringDedup::is_candidate_from_evacuation(...) {// If the object is in Eden Region, And the type is java.lang.stringIf (from_young && java_lang_String::is_instance_inlined(obj)) {// If the object is to be copied to Survivor Region, And the age is less than the threshold if (to_young && obj - > age () = = StringDeduplicationAgeThreshold) {return true; // Add G1StringDedupQueue as a candidate}// If the object is going to be promoted to the Old Region and is younger than the threshold if (! to_young && obj->age() < StringDeduplicationAgeThreshold) {return true; G1StringDedupQueue}}return false; }void G1StringDedup::enqueue_from_evacuation(...) {if (is_candidate_from_evacuation(...) ) {G1StringDedupQueue::push(worker_id, java_string); }}Copy the code

G1 copies all surviving objects from Eden to Survivor Region, All from Eden promotion to Old Region and younger than – XX: StringDeduplicationAgeThreshold objects are in G1StringDedupQueue waiting for string to deal with heavy thread. String to heavy thread StringDedupThread namely, it is found in the queue to heavy will pop up after candidate for object, then calls the StringDedupTable: : deduplicate, such as the code shown in listing 11 to 9:

Listing 11-9 StringDedupTable: : deduplicate

void StringDedupTable::deduplicate(...) TypeArrayOop value = java_lang_String::value(javA_string); if (value == NULL) {stat->inc_skipped(); return; }... TypeArrayOop existing_value = lookup_or_add(value, latin1, hash); If (oopDesc::equals_raw(existing_value, value)) {stat->inc_known(); return; }... If (existing_value!) if (existing_value! = NULL) {java_lang_String::set_value(java_string, existing_value); stat->deduped(value, size_in_bytes); }}Copy the code