< 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 >