Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docs/code/detailed explanation for "Ext Root Scanning" on G1 gc?

1] Can anyone point to docs or explain in detail how "Ext Root Scanning" works in G1 GC, especially for JNI handles? (Specific to Java 7 if possible please)

2] Bonus: How different can we expect the openJDK code for G1 gc to be from Hotspot? If we can expect this to be the same, please can you point to relevant parts of the openJDK code for G1 GC ext root scanning?

thanks

like image 323
carlsborg Avatar asked Apr 25 '17 16:04

carlsborg


1 Answers

Overview

From Oracle Doc:

When performing garbage collections, G1 operates in a manner similar to the CMS collector. G1 performs a concurrent global marking phase to determine the liveness of objects throughout the heap.

And external root region scanning is one of the phase of marking process.

From Java Performance Companion:

During this phase the external (off-heap) roots such as the JVM’s system dictionary, VM data structures, JNI thread handles, hardware registers, global variables, and thread stack roots are scanned to find out if any point into the current pause’s collection set (CSet).

Detail and Code

Yes, we can expect the code for g1 of openjdk and hotspot to be same as here stated. So we can explain the detail process by reading source code.

From G1CollectedHeap:

void
G1CollectedHeap::
g1_process_strong_roots(bool collecting_perm_gen,
                        SharedHeap::ScanningOption so,
                        OopClosure* scan_non_heap_roots,
                        OopsInHeapRegionClosure* scan_rs,
                        OopsInGenClosure* scan_perm,
                        int worker_i) {
  //...
  process_strong_roots(false, // no scoping; this is parallel code
                       collecting_perm_gen, so,
                       &buf_scan_non_heap_roots,
                       &eager_scan_code_roots,
                       &buf_scan_perm);
  //...
}

Then in process_strong_roots:

  // Global (strong) JNI handles
  if (!_process_strong_tasks->is_task_claimed(SH_PS_JNIHandles_oops_do))
    JNIHandles::oops_do(roots);

And the core process about JNI: it iterate the JNI handles block and find out if this handle block's oops (oop: Java's reference abstraction) is point to heap area, which means whether this JNI oop can be a root for gc.

for (JNIHandleBlock* current = current_chain; current != NULL;
     current = current->_next) {
  assert(current == current_chain || current->pop_frame_link() == NULL,
    "only blocks first in chain should have pop frame link set");
  for (int index = 0; index < current->_top; index++) {
    oop* root = &(current->_handles)[index];
    oop value = *root;
    // traverse heap pointers only, not deleted handles or free list
    // pointers
    if (value != NULL && Universe::heap()->is_in_reserved(value)) {
      f->do_oop(root);
    }
  }
  // the next handle block is valid only if current block is full
  if (current->_top < block_size_in_oops) {
    break;
  }
}

And then, this root is remembered in a array, processed by OopClosure when array is full, in which case, iterate the reference of root to mark live objects.

More:

  • Code with comments
like image 118
Tony Avatar answered Oct 21 '22 04:10

Tony