< prev index next >

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

Print this page
rev 49484 : imported patch 8197573-remove-secondary-free-list
rev 49485 : imported patch 8197573-stefanj-review2
rev 49493 : imported patch 8199326-remove-gc-time-stamp-logic-only
rev 49494 : imported patch 8199742-collectorstate-fixes
rev 49496 : imported patch 8151171-renamings
rev 49497 : [mq]: 8200234-g1concurrentmark-refactorings

@@ -28,11 +28,10 @@
 #include "code/codeCache.hpp"
 #include "gc/g1/concurrentMarkThread.inline.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1CollectorState.hpp"
 #include "gc/g1/g1ConcurrentMark.inline.hpp"
-#include "gc/g1/g1HeapVerifier.hpp"
 #include "gc/g1/g1OopClosures.inline.hpp"
 #include "gc/g1/g1Policy.hpp"
 #include "gc/g1/g1RegionMarkStatsCache.inline.hpp"
 #include "gc/g1/g1StringDedup.hpp"
 #include "gc/g1/heapRegion.inline.hpp"

@@ -490,10 +489,12 @@
   reset_at_marking_complete();
   _completed_initialization = true;
 }
 
 void G1ConcurrentMark::reset() {
+  _has_aborted = false;
+
   reset_marking_for_restart();
 
   // Reset all tasks, since different phases will use different number of active
   // threads. So, it's easiest to have all of them ready.
   for (uint i = 0; i < _max_num_tasks; ++i) {

@@ -517,19 +518,11 @@
   }
   _top_at_rebuild_starts[region_idx] = NULL;
   _region_mark_stats[region_idx].clear();
 }
 
-void G1ConcurrentMark::humongous_object_eagerly_reclaimed(HeapRegion* r) {
-  assert_at_safepoint_on_vm_thread();
-
-  // Need to clear mark bit of the humongous object if already set and during a marking cycle.
-  if (_next_mark_bitmap->is_marked(r->bottom())) {
-    _next_mark_bitmap->clear(r->bottom());
-  }
-
-  // Clear any statistics about the region gathered so far.
+void G1ConcurrentMark::clear_statistics(HeapRegion* r) {
   uint const region_idx = r->hrm_index();
   if (r->is_humongous()) {
     assert(r->is_starts_humongous(), "Got humongous continues region here");
     uint const size_in_regions = (uint)_g1h->humongous_obj_size_in_regions(oop(r->humongous_start_region()->bottom())->size());
     for (uint j = region_idx; j < (region_idx + size_in_regions); j++) {

@@ -538,10 +531,27 @@
   } else {
     clear_statistics_in_region(region_idx);
   }
 }
 
+void G1ConcurrentMark::humongous_object_eagerly_reclaimed(HeapRegion* r) {
+  assert_at_safepoint_on_vm_thread();
+
+  G1CMBitMap* const bitmap = _g1h->collector_state()->mark_or_rebuild_in_progress() ? _next_mark_bitmap : _prev_mark_bitmap;
+  // Need to clear mark bit of the humongous object if already set and during a marking cycle.
+  if (bitmap->is_marked(r->bottom())) {
+    bitmap->clear(r->bottom());
+  }
+
+  if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) {
+    return;
+  }
+
+  // Clear any statistics about the region gathered so far.
+  clear_statistics(r);
+}
+
 void G1ConcurrentMark::reset_marking_for_restart() {
   _global_mark_stack.set_empty();
 
   // Expand the marking stack, if we have to and if we can.
   if (has_overflown()) {

@@ -743,12 +753,10 @@
     return false;
   }
 };
 
 void G1ConcurrentMark::pre_initial_mark() {
-  _has_aborted = false;
-
   // Initialize marking structures. This has to be done in a STW phase.
   reset();
 
   // For each region note start of marking.
   NoteStartOfMarkHRClosure startcl;

@@ -951,10 +959,12 @@
 
   _g1h->trace_heap_before_gc(_gc_tracer_cm);
 }
 
 void G1ConcurrentMark::concurrent_cycle_end() {
+  _g1h->collector_state()->set_clearing_next_bitmap(false);
+
   _g1h->trace_heap_after_gc(_gc_tracer_cm);
 
   if (has_aborted()) {
     log_info(gc, marking)("Concurrent Mark Abort");
     _gc_tracer_cm->report_concurrent_mode_failure();

@@ -984,10 +994,28 @@
   G1CMConcurrentMarkingTask marking_task(this);
   _concurrent_workers->run_task(&marking_task);
   print_stats();
 }
 
+void G1ConcurrentMark::verify_during_pause(G1HeapVerifier::G1VerifyType type, VerifyOption vo, const char* caller) {
+  G1HeapVerifier* verifier = _g1h->verifier();
+
+  verifier->verify_region_sets_optional();
+
+  if (VerifyDuringGC) {
+    GCTraceTime(Debug, gc, phases) trace(caller, _gc_timer_cm);
+
+    size_t const BufLen = 512;
+    char buffer[BufLen];
+
+    os::snprintf(buffer, BufLen, "During GC (%s)", caller);
+    verifier->verify(type, vo, buffer);
+  }
+
+  verifier->check_bitmaps(caller);
+}
+
 class G1UpdateRemSetTrackingBeforeRebuild : public HeapRegionClosure {
   G1CollectedHeap* _g1h;
   G1ConcurrentMark* _cm;
 
   uint _num_regions_selected_for_rebuild;  // The number of regions actually selected for rebuild.

@@ -1033,39 +1061,28 @@
   // have ended up here as the Remark VM operation has been scheduled already.
   if (has_aborted()) {
     return;
   }
 
-  if (VerifyDuringGC) {
-    _g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "During GC (Remark before)");
-  }
-  _g1h->verifier()->check_bitmaps("Remark Start");
-
   G1Policy* g1p = _g1h->g1_policy();
   g1p->record_concurrent_mark_remark_start();
 
   double start = os::elapsedTime();
 
+  verify_during_pause(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "Remark before");
+
+  {
+    GCTraceTime(Debug, gc, phases) trace("Finalize Marking", _gc_timer_cm);
   finalize_marking();
+  }
 
   double mark_work_end = os::elapsedTime();
 
+  bool const mark_finished = !has_overflown();
+  if (mark_finished) {
   weak_refs_work(false /* clear_all_soft_refs */);
 
-  if (has_overflown()) {
-    // We overflowed.  Restart concurrent marking.
-    _restart_for_overflow = true;
-
-    // Verify the heap w.r.t. the previous marking bitmap.
-    if (VerifyDuringGC) {
-      _g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "During GC (Remark overflow)");
-    }
-
-    // Clear the marking state because we will be restarting
-    // marking due to overflowing the global mark stack.
-    reset_marking_for_restart();
-  } else {
     SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
     // We're done with marking.
     // This is the end of the marking cycle, we're expected all
     // threads to have SATB queues with active set to true.
     satb_mq_set.set_active_all_threads(false, /* new active value */

@@ -1082,29 +1099,38 @@
       _g1h->heap_region_iterate(&cl);
       log_debug(gc, remset, tracking)("Remembered Set Tracking update regions total %u, selected %u",
                                       _g1h->num_regions(), cl.num_selected_for_rebuild());
     }
 
-    if (VerifyDuringGC) {
-      _g1h->verifier()->verify(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UseNextMarking, "During GC (Remark after)");
-    }
-    _g1h->verifier()->check_bitmaps("Remark End");
+    verify_during_pause(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UseNextMarking, "Remark after");
+
     assert(!restart_for_overflow(), "sanity");
     // Completely reset the marking state since marking completed
     reset_at_marking_complete();
+  } else {
+    // We overflowed.  Restart concurrent marking.
+    _restart_for_overflow = true;
+
+    verify_during_pause(G1HeapVerifier::G1VerifyRemark, VerifyOption_G1UsePrevMarking, "Remark overflow");
+
+    // Clear the marking state because we will be restarting
+    // marking due to overflowing the global mark stack.
+    reset_marking_for_restart();
+  }
+
+  {
+    GCTraceTime(Debug, gc, phases)("Report Object Count");
+    report_object_count();
   }
 
   // Statistics
   double now = os::elapsedTime();
   _remark_mark_times.add((mark_work_end - start) * 1000.0);
   _remark_weak_ref_times.add((now - mark_work_end) * 1000.0);
   _remark_times.add((now - start) * 1000.0);
 
   g1p->record_concurrent_mark_remark_end();
-
-  G1CMIsAliveClosure is_alive(_g1h);
-  _gc_tracer_cm->report_object_count_after_gc(&is_alive);
 }
 
 class G1CleanupTask : public AbstractGangTask {
   // Per-region work during the Cleanup pause.
   class G1CleanupRegionsClosure : public HeapRegionClosure {

@@ -1142,10 +1168,12 @@
         } else {
           _old_regions_removed++;
           _g1h->free_region(hr, _local_cleanup_list, false /* skip_remset */, false /* skip_hcc */, true /* locked */);
         }
         hr->clear_cardtable();
+        _g1h->concurrent_mark()->clear_statistics_in_region(hr->hrm_index());
+        log_trace(gc)("Reclaimed empty region %u (%s) bot " PTR_FORMAT, hr->hrm_index(), hr->get_short_type_str(), p2i(hr->bottom()));
       } else {
         hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task);
       }
 
       return false;

@@ -1195,10 +1223,11 @@
 
   G1CleanupTask cl(_g1h, &empty_regions_list, workers->active_workers());
   workers->run_task(&cl);
 
   if (!empty_regions_list.is_empty()) {
+    log_debug(gc)("Reclaimed %u empty regions", empty_regions_list.length());
     // Now print the empty regions list.
     G1HRPrinter* hrp = _g1h->hr_printer();
     if (hrp->is_active()) {
       FreeRegionListIterator iter(&empty_regions_list);
       while (iter.more_available()) {

@@ -1217,32 +1246,23 @@
   // If a full collection has happened, we shouldn't do this.
   if (has_aborted()) {
     return;
   }
 
-  _g1h->verifier()->verify_region_sets_optional();
-
-  if (VerifyDuringGC) { // While rebuilding the remembered set we used the next marking...
-    _g1h->verifier()->verify(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UseNextMarking, "During GC (Cleanup before)");
-  }
-  _g1h->verifier()->check_bitmaps("Cleanup Start");
-
   G1Policy* g1p = _g1h->g1_policy();
   g1p->record_concurrent_mark_cleanup_start();
 
   double start = os::elapsedTime();
 
+  verify_during_pause(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UseNextMarking, "Cleanup before");
+
   {
     GCTraceTime(Debug, gc, phases)("Update Remembered Set Tracking After Rebuild");
     G1UpdateRemSetTrackingAfterRebuild cl(_g1h);
     _g1h->heap_region_iterate(&cl);
   }
 
-  double count_end = os::elapsedTime();
-  double this_final_counting_time = (count_end - start);
-  _total_cleanup_time += this_final_counting_time;
-
   if (log_is_enabled(Trace, gc, liveness)) {
     G1PrintRegionLivenessInfoClosure cl("Post-Cleanup");
     _g1h->heap_region_iterate(&cl);
   }
 

@@ -1251,44 +1271,40 @@
   {
     GCTraceTime(Debug, gc, phases)("Reclaim Empty Regions");
     reclaim_empty_regions();
   }
 
-  {
-    GCTraceTime(Debug, gc, phases)("Finalize Concurrent Mark Cleanup");
-    _g1h->g1_policy()->record_concurrent_mark_cleanup_end();
-  }
-
-  // Statistics.
-  double end = os::elapsedTime();
-  _cleanup_times.add((end - start) * 1000.0);
-
   // Cleanup will have freed any regions completely full of garbage.
   // Update the soft reference policy with the new heap occupancy.
   Universe::update_heap_info_at_gc();
 
-  if (VerifyDuringGC) {
-    _g1h->verifier()->verify(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UsePrevMarking, "During GC (Cleanup after)");
-  }
-
-  _g1h->verifier()->check_bitmaps("Cleanup End");
-
-  _g1h->verifier()->verify_region_sets_optional();
-
-  // We need to make this be a "collection" so any collection pause that
-  // races with it goes around and waits for completeCleanup to finish.
-  _g1h->increment_total_collections();
-
   // Clean out dead classes and update Metaspace sizes.
   if (ClassUnloadingWithConcurrentMark) {
+    GCTraceTime(Debug, gc, phases)("Purge Metaspace");
     ClassLoaderDataGraph::purge();
   }
   MetaspaceGC::compute_new_size();
 
   // We reclaimed old regions so we should calculate the sizes to make
   // sure we update the old gen/space data.
   _g1h->g1mm()->update_sizes();
+
+  verify_during_pause(G1HeapVerifier::G1VerifyCleanup, VerifyOption_G1UsePrevMarking, "Cleanup after");
+
+  // We need to make this be a "collection" so any collection pause that
+  // races with it goes around and waits for Cleanup to finish.
+  _g1h->increment_total_collections();
+
+  // Local statistics
+  double recent_cleanup_time = (os::elapsedTime() - start);
+  _total_cleanup_time += recent_cleanup_time;
+  _cleanup_times.add(recent_cleanup_time);
+
+  {
+    GCTraceTime(Debug, gc, phases)("Finalize Concurrent Mark Cleanup");
+    _g1h->g1_policy()->record_concurrent_mark_cleanup_end();
+  }
 }
 
 // Supporting Object and Oop closures for reference discovery
 // and processing in during marking
 

@@ -1499,20 +1515,10 @@
   _cm->set_concurrency(_active_workers);
   _workers->run_task(&enq_task_proxy);
 }
 
 void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
-  if (has_overflown()) {
-    // Skip processing the discovered references if we have
-    // overflown the global marking stack. Reference objects
-    // only get discovered once so it is OK to not
-    // de-populate the discovered reference lists. We could have,
-    // but the only benefit would be that, when marking restarts,
-    // less reference objects are discovered.
-    return;
-  }
-
   ResourceMark rm;
   HandleMark   hm;
 
   // Is alive closure.
   G1CMIsAliveClosure g1_is_alive(_g1h);

@@ -1627,14 +1633,20 @@
     // class unloading is disabled.
     _g1h->partial_cleaning(&g1_is_alive, false, false, G1StringDedup::is_enabled());
   }
 }
 
+void G1ConcurrentMark::report_object_count() {
+  G1CMIsAliveClosure is_alive(_g1h);
+  _gc_tracer_cm->report_object_count_after_gc(&is_alive);
+}
+
 void G1ConcurrentMark::swap_mark_bitmaps() {
   G1CMBitMap* temp = _prev_mark_bitmap;
   _prev_mark_bitmap = _next_mark_bitmap;
   _next_mark_bitmap = temp;
+  _g1h->collector_state()->set_clearing_next_bitmap(true);
 }
 
 // Closure for marking entries in SATB buffers.
 class G1CMSATBBufferClosure : public SATBBufferClosure {
 private:

@@ -1729,12 +1741,10 @@
 
 void G1ConcurrentMark::finalize_marking() {
   ResourceMark rm;
   HandleMark   hm;
 
-  GCTraceTime(Debug, gc, phases) trace("Finalize Marking", _gc_timer_cm);
-
   _g1h->ensure_parsability(false);
 
   // this is remark, so we'll use up all active threads
   uint active_workers = _g1h->workers()->active_workers();
   set_concurrency_and_phase(active_workers, false /* concurrent */);
< prev index next >