< prev index next >

src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp

Print this page
rev 52572 : JDK-8212657: Implementation of JDK-8204089 Promptly Return Unused Committed Memory from G1
Summary: Issue optional, default enabled, concurrent cycles when the VM is idle to reclaim unused internal and Java heap memory.
Reviewed-by:
Contributed-by: Rodrigo Bruno <rbruno@gsd.inesc-id.pt>, Ruslan Synytsky <rs@jelastic.com>, Thomas Schatzl <thomas.schatzl@oracle.com>
rev 52573 : [mq]: 8212657-stefanj-review

@@ -23,10 +23,12 @@
  */
 
 #include "precompiled.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1CollectionSet.hpp"
+#include "gc/g1/g1ConcurrentMark.inline.hpp"
+#include "gc/g1/g1ConcurrentMarkThread.inline.hpp"
 #include "gc/g1/g1Policy.hpp"
 #include "gc/g1/g1YoungRemSetSamplingThread.hpp"
 #include "gc/g1/heapRegion.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"

@@ -35,23 +37,62 @@
 G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() :
     ConcurrentGCThread(),
     _monitor(Mutex::nonleaf,
              "G1YoungRemSetSamplingThread monitor",
              true,
-             Monitor::_safepoint_check_never) {
+             Monitor::_safepoint_check_never),
+    _last_periodic_gc_attempt_s(os::elapsedTime()) {
   set_name("G1 Young RemSet Sampling");
   create_and_start();
 }
 
 void G1YoungRemSetSamplingThread::sleep_before_next_cycle() {
   MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
   if (!should_terminate()) {
-    uintx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be?
+    uintx waitms = G1ConcRefinementServiceIntervalMillis;
     _monitor.wait(Mutex::_no_safepoint_check_flag, waitms);
   }
 }
 
+bool G1YoungRemSetSamplingThread::should_start_periodic_gc() {
+  // If we are currently in a concurrent mark we are going to uncommit memory soon.
+  if (G1CollectedHeap::heap()->concurrent_mark()->cm_thread()->during_cycle()) {
+    log_debug(gc, periodic)("Concurrent cycle in progress. Skipping.");
+    return false;
+  }
+
+  // Check if enough time has passed since the last GC.
+  uintx time_since_last_gc;
+  if ((G1PeriodicGCInterval == 0) ||
+      ((time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc()) < G1PeriodicGCInterval)) {
+    log_debug(gc, periodic)("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.",
+                            time_since_last_gc, G1PeriodicGCInterval);
+    return false;
+  }
+
+  // Check if load is lower than max.
+  double recent_load;
+  if ((G1PeriodicGCSystemLoadThreshold > 0) &&
+      (os::loadavg(&recent_load, 1) == -1 || recent_load > G1PeriodicGCSystemLoadThreshold)) {
+    log_debug(gc, periodic)("Load %1.2f is higher than threshold " UINTX_FORMAT ". Skipping.",
+                            recent_load, G1PeriodicGCSystemLoadThreshold);
+    return false;
+  }
+
+  return true;
+}
+
+void G1YoungRemSetSamplingThread::check_for_periodic_gc(){
+  if ((os::elapsedTime() - _last_periodic_gc_attempt_s) > (G1PeriodicGCInterval / 1000.0)) {
+    log_debug(gc, periodic)("Checking for periodic GC.");
+    if (should_start_periodic_gc()) {
+      Universe::heap()->collect(GCCause::_g1_periodic_collection);
+    }
+    _last_periodic_gc_attempt_s = os::elapsedTime();
+  }
+}
+
 void G1YoungRemSetSamplingThread::run_service() {
   double vtime_start = os::elapsedVTime();
 
   while (!should_terminate()) {
     sample_young_list_rs_lengths();

@@ -60,10 +101,12 @@
       _vtime_accum = (os::elapsedVTime() - vtime_start);
     } else {
       _vtime_accum = 0.0;
     }
 
+    check_for_periodic_gc();
+
     sleep_before_next_cycle();
   }
 }
 
 void G1YoungRemSetSamplingThread::stop_service() {
< prev index next >