src/share/vm/gc_implementation/g1/concurrentMark.cpp

Print this page
rev 4278 : [mq]: 8009536-fix
rev 4279 : 8009940: G1: assert(_finger == _heap_end) failed, concurrentMark.cpp:809
Summary: Skip reference processing if the global marking stack overflows during remark. Do not call set_phase() from within parallel reference processing; use reset_for_reuse() instead. CMTask-0 should reset the marking state only during the concurrent phase of the marking cycle; if an overflow occurs at any stage during the remark, the marking state will be reset after reference processing.

@@ -782,19 +782,23 @@
     CMTaskQueue* queue = _task_queues->queue(i);
     queue->set_empty();
   }
 }
 
-void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) {
+void ConcurrentMark::set_concurrency(uint active_tasks) {
   assert(active_tasks <= _max_worker_id, "we should not have more");
 
   _active_tasks = active_tasks;
   // Need to update the three data structures below according to the
   // number of active threads for this phase.
   _terminator   = ParallelTaskTerminator((int) active_tasks, _task_queues);
   _first_overflow_barrier_sync.set_n_workers((int) active_tasks);
   _second_overflow_barrier_sync.set_n_workers((int) active_tasks);
+}
+
+void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) {
+  set_concurrency(active_tasks);
 
   _concurrent = concurrent;
   // We propagate this to all tasks, not just the active ones.
   for (uint i = 0; i < _max_worker_id; ++i)
     _tasks[i]->set_concurrent(concurrent);

@@ -804,11 +808,13 @@
   } else {
     // We currently assume that the concurrent flag has been set to
     // false before we start remark. At this point we should also be
     // in a STW phase.
     assert(!concurrent_marking_in_progress(), "invariant");
-    assert(_finger == _heap_end, "only way to get here");
+    assert(_finger == _heap_end,
+           err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT,
+                   _finger, _heap_end));
     update_g1_committed(true);
   }
 }
 
 void ConcurrentMark::set_non_marking_state() {

@@ -972,26 +978,34 @@
 
   if (verbose_low()) {
     gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
   }
 
+  // If we're executing the concurrent phase of marking, reset the marking
+  // state; otherwise the marking state is reset after reference processing,
+  // during the remark pause.
+  // If we reset here as a result of an overflow during the remark we will
+  // see assertion failures from any subsequent set_concurrency_and_phase()
+  // calls.
+  if (concurrent()) {
   // let the task associated with with worker 0 do this
   if (worker_id == 0) {
     // task 0 is responsible for clearing the global data structures
     // We should be here because of an overflow. During STW we should
     // not clear the overflow flag since we rely on it being true when
     // we exit this method to abort the pause and restart concurent
     // marking.
-    reset_marking_state(concurrent() /* clear_overflow */);
+      reset_marking_state(true /* clear_overflow */);
     force_overflow()->update();
 
     if (G1Log::fine()) {
       gclog_or_tty->date_stamp(PrintGCDateStamps);
       gclog_or_tty->stamp(PrintGCTimeStamps);
       gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
     }
   }
+  }
 
   // after this, each task should reset its own data structures then
   // then go into the second barrier
 }
 

@@ -1005,11 +1019,11 @@
   }
   _second_overflow_barrier_sync.enter();
   if (concurrent()) {
     ConcurrentGCThread::stsJoin();
   }
-  // at this point everything should be re-initialised and ready to go
+  // at this point everything should be re-initialized and ready to go
 
   if (verbose_low()) {
     gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
   }
 }

@@ -1221,12 +1235,12 @@
   assert(parallel_marking_threads() <= max_parallel_marking_threads(),
     "Maximum number of marking threads exceeded");
 
   uint active_workers = MAX2(1U, parallel_marking_threads());
 
-  // Parallel task terminator is set in "set_phase()"
-  set_phase(active_workers, true /* concurrent */);
+  // Parallel task terminator is set in "set_concurrency_and_phase()"
+  set_concurrency_and_phase(active_workers, true /* concurrent */);
 
   CMConcurrentMarkingTask markingTask(this, cmThread());
   if (use_parallel_marking_threads()) {
     _parallel_workers->set_active_workers((int)active_workers);
     // Don't set _n_par_threads because it affects MT in proceess_strong_roots()

@@ -2359,13 +2373,15 @@
   assert(_workers != NULL, "Need parallel worker threads.");
   assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
 
   G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
 
-  // We need to reset the phase for each task execution so that
-  // the termination protocol of CMTask::do_marking_step works.
-  _cm->set_phase(_active_workers, false /* concurrent */);
+  // We need to reset the concurrency level before each
+  // proxy task execution, so that the termination protocol
+  // and overflow handling in CMTask::do_marking_step() knows
+  // how many workers to wait for.
+  _cm->set_concurrency(_active_workers);
   _g1h->set_par_threads(_active_workers);
   _workers->run_task(&proc_task_proxy);
   _g1h->set_par_threads(0);
 }
 

@@ -2387,16 +2403,33 @@
   assert(_workers != NULL, "Need parallel worker threads.");
   assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
 
   G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task);
 
+  // Not strictly necessary but...
+  //
+  // We need to reset the concurrency level before each
+  // proxy task execution, so that the termination protocol
+  // and overflow handling in CMTask::do_marking_step() knows
+  // how many workers to wait for.
+  _cm->set_concurrency(_active_workers);
   _g1h->set_par_threads(_active_workers);
   _workers->run_task(&enq_task_proxy);
   _g1h->set_par_threads(0);
 }
 
 void ConcurrentMark::weakRefsWork(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;
 
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
 

@@ -2448,10 +2481,14 @@
     // Parallel processing task executor.
     G1CMRefProcTaskExecutor par_task_executor(g1h, this,
                                               g1h->workers(), active_workers);
     AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL);
 
+    // Set the concurrency level. The phase was already set prior to
+    // executing the remark task.
+    set_concurrency(active_workers);
+
     // Set the degree of MT processing here.  If the discovery was done MT,
     // the number of threads involved during discovery could differ from
     // the number of active workers.  This is OK as long as the discovered
     // Reference lists are balanced (see balance_all_queues() and balance_queues()).
     rp->set_active_mt_degree(active_workers);

@@ -2538,11 +2575,11 @@
     if (active_workers == 0) {
       assert(active_workers > 0, "Should have been set earlier");
       active_workers = (uint) ParallelGCThreads;
       g1h->workers()->set_active_workers(active_workers);
     }
-    set_phase(active_workers, false /* concurrent */);
+    set_concurrency_and_phase(active_workers, false /* concurrent */);
     // Leave _parallel_marking_threads at it's
     // value originally calculated in the ConcurrentMark
     // constructor and pass values of the active workers
     // through the gang in the task.
 

@@ -2554,11 +2591,11 @@
     g1h->workers()->run_task(&remarkTask);
     g1h->set_par_threads(0);
   } else {
     G1CollectedHeap::StrongRootsScope srs(g1h);
     uint active_workers = 1;
-    set_phase(active_workers, false /* concurrent */);
+    set_concurrency_and_phase(active_workers, false /* concurrent */);
 
     // Note - if there's no work gang then the VMThread will be
     // the thread to execute the remark - serially. We have
     // to pass true for the is_serial parameter so that
     // CMTask::do_marking_step() doesn't enter the sync

@@ -3945,11 +3982,11 @@
       (1) When the marking phase has been aborted (after a Full GC).
 
       (2) When a global overflow (on the global stack) has been
       triggered. Before the task aborts, it will actually sync up with
       the other tasks to ensure that all the marking data structures
-      (local queues, stacks, fingers etc.)  are re-initialised so that
+      (local queues, stacks, fingers etc.)  are re-initialized so that
       when do_marking_step() completes, the marking phase can
       immediately restart.
 
       (3) When enough completed SATB buffers are available. The
       do_marking_step() method only tries to drain SATB buffers right

@@ -4392,11 +4429,12 @@
 
       if (!is_serial) {
         // ...and enter the second barrier.
         _cm->enter_second_sync_barrier(_worker_id);
       }
-      // At this point everything has bee re-initialised and we're
+      // At this point, if we're during the concurrent phase of
+      // marking, everything has been re-initialized and we're
       // ready to restart.
     }
 
     if (_cm->verbose_low()) {
       gclog_or_tty->print_cr("[%u] <<<<<<<<<< ABORTING, target = %1.2lfms, "