Thu, 22 Sep 2011 10:57:37 -0700
6484982: G1: process references during evacuation pauses
Summary: G1 now uses two reference processors - one is used by concurrent marking and the other is used by STW GCs (both full and incremental evacuation pauses). In an evacuation pause, the reference processor is embedded into the closures used to scan objects. Doing so causes causes reference objects to be 'discovered' by the reference processor. At the end of the evacuation pause, these discovered reference objects are processed - preserving (and copying) referent objects (and their reachable graphs) as appropriate.
Reviewed-by: ysr, jwilhelm, brutisso, stefank, tonyp
1 /*
2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 #include "precompiled.hpp"
26 #include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
28 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
29 #include "gc_implementation/g1/g1MMUTracker.hpp"
30 #include "gc_implementation/g1/vm_operations_g1.hpp"
31 #include "memory/resourceArea.hpp"
32 #include "runtime/vmThread.hpp"
34 // ======= Concurrent Mark Thread ========
36 // The CM thread is created when the G1 garbage collector is used
38 SurrogateLockerThread*
39 ConcurrentMarkThread::_slt = NULL;
41 ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
42 ConcurrentGCThread(),
43 _cm(cm),
44 _started(false),
45 _in_progress(false),
46 _vtime_accum(0.0),
47 _vtime_mark_accum(0.0),
48 _vtime_count_accum(0.0)
49 {
50 create_and_start();
51 }
53 class CMCheckpointRootsFinalClosure: public VoidClosure {
55 ConcurrentMark* _cm;
56 public:
58 CMCheckpointRootsFinalClosure(ConcurrentMark* cm) :
59 _cm(cm) {}
61 void do_void(){
62 _cm->checkpointRootsFinal(false); // !clear_all_soft_refs
63 }
64 };
66 class CMCleanUp: public VoidClosure {
67 ConcurrentMark* _cm;
68 public:
70 CMCleanUp(ConcurrentMark* cm) :
71 _cm(cm) {}
73 void do_void(){
74 _cm->cleanup();
75 }
76 };
80 void ConcurrentMarkThread::run() {
81 initialize_in_thread();
82 _vtime_start = os::elapsedVTime();
83 wait_for_universe_init();
85 G1CollectedHeap* g1h = G1CollectedHeap::heap();
86 G1CollectorPolicy* g1_policy = g1h->g1_policy();
87 G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
88 Thread *current_thread = Thread::current();
90 while (!_should_terminate) {
91 // wait until started is set.
92 sleepBeforeNextCycle();
93 {
94 ResourceMark rm;
95 HandleMark hm;
96 double cycle_start = os::elapsedVTime();
97 double mark_start_sec = os::elapsedTime();
98 char verbose_str[128];
100 if (PrintGC) {
101 gclog_or_tty->date_stamp(PrintGCDateStamps);
102 gclog_or_tty->stamp(PrintGCTimeStamps);
103 gclog_or_tty->print_cr("[GC concurrent-mark-start]");
104 }
106 int iter = 0;
107 do {
108 iter++;
109 if (!cm()->has_aborted()) {
110 _cm->markFromRoots();
111 }
113 double mark_end_time = os::elapsedVTime();
114 double mark_end_sec = os::elapsedTime();
115 _vtime_mark_accum += (mark_end_time - cycle_start);
116 if (!cm()->has_aborted()) {
117 if (g1_policy->adaptive_young_list_length()) {
118 double now = os::elapsedTime();
119 double remark_prediction_ms = g1_policy->predict_remark_time_ms();
120 jlong sleep_time_ms = mmu_tracker->when_ms(now, remark_prediction_ms);
121 os::sleep(current_thread, sleep_time_ms, false);
122 }
124 if (PrintGC) {
125 gclog_or_tty->date_stamp(PrintGCDateStamps);
126 gclog_or_tty->stamp(PrintGCTimeStamps);
127 gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]",
128 mark_end_sec - mark_start_sec);
129 }
131 CMCheckpointRootsFinalClosure final_cl(_cm);
132 sprintf(verbose_str, "GC remark");
133 VM_CGC_Operation op(&final_cl, verbose_str);
134 VMThread::execute(&op);
135 }
136 if (cm()->restart_for_overflow() &&
137 G1TraceMarkStackOverflow) {
138 gclog_or_tty->print_cr("Restarting conc marking because of MS overflow "
139 "in remark (restart #%d).", iter);
140 }
142 if (cm()->restart_for_overflow()) {
143 if (PrintGC) {
144 gclog_or_tty->date_stamp(PrintGCDateStamps);
145 gclog_or_tty->stamp(PrintGCTimeStamps);
146 gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]");
147 }
148 }
149 } while (cm()->restart_for_overflow());
150 double counting_start_time = os::elapsedVTime();
152 // YSR: These look dubious (i.e. redundant) !!! FIX ME
153 slt()->manipulatePLL(SurrogateLockerThread::acquirePLL);
154 slt()->manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
156 if (!cm()->has_aborted()) {
157 double count_start_sec = os::elapsedTime();
158 if (PrintGC) {
159 gclog_or_tty->date_stamp(PrintGCDateStamps);
160 gclog_or_tty->stamp(PrintGCTimeStamps);
161 gclog_or_tty->print_cr("[GC concurrent-count-start]");
162 }
164 _sts.join();
165 _cm->calcDesiredRegions();
166 _sts.leave();
168 if (!cm()->has_aborted()) {
169 double count_end_sec = os::elapsedTime();
170 if (PrintGC) {
171 gclog_or_tty->date_stamp(PrintGCDateStamps);
172 gclog_or_tty->stamp(PrintGCTimeStamps);
173 gclog_or_tty->print_cr("[GC concurrent-count-end, %1.7lf]",
174 count_end_sec - count_start_sec);
175 }
176 }
177 }
178 double end_time = os::elapsedVTime();
179 _vtime_count_accum += (end_time - counting_start_time);
180 // Update the total virtual time before doing this, since it will try
181 // to measure it to get the vtime for this marking. We purposely
182 // neglect the presumably-short "completeCleanup" phase here.
183 _vtime_accum = (end_time - _vtime_start);
184 if (!cm()->has_aborted()) {
185 if (g1_policy->adaptive_young_list_length()) {
186 double now = os::elapsedTime();
187 double cleanup_prediction_ms = g1_policy->predict_cleanup_time_ms();
188 jlong sleep_time_ms = mmu_tracker->when_ms(now, cleanup_prediction_ms);
189 os::sleep(current_thread, sleep_time_ms, false);
190 }
192 CMCleanUp cl_cl(_cm);
193 sprintf(verbose_str, "GC cleanup");
194 VM_CGC_Operation op(&cl_cl, verbose_str);
195 VMThread::execute(&op);
196 } else {
197 g1h->set_marking_complete();
198 }
200 // Check if cleanup set the free_regions_coming flag. If it
201 // hasn't, we can just skip the next step.
202 if (g1h->free_regions_coming()) {
203 // The following will finish freeing up any regions that we
204 // found to be empty during cleanup. We'll do this part
205 // without joining the suspendible set. If an evacuation pause
206 // takes place, then we would carry on freeing regions in
207 // case they are needed by the pause. If a Full GC takes
208 // place, it would wait for us to process the regions
209 // reclaimed by cleanup.
211 double cleanup_start_sec = os::elapsedTime();
212 if (PrintGC) {
213 gclog_or_tty->date_stamp(PrintGCDateStamps);
214 gclog_or_tty->stamp(PrintGCTimeStamps);
215 gclog_or_tty->print_cr("[GC concurrent-cleanup-start]");
216 }
218 // Now do the remainder of the cleanup operation.
219 _cm->completeCleanup();
220 // Notify anyone who's waiting that there are no more free
221 // regions coming. We have to do this before we join the STS,
222 // otherwise we might deadlock: a GC worker could be blocked
223 // waiting for the notification whereas this thread will be
224 // blocked for the pause to finish while it's trying to join
225 // the STS, which is conditional on the GC workers finishing.
226 g1h->reset_free_regions_coming();
228 _sts.join();
229 g1_policy->record_concurrent_mark_cleanup_completed();
230 _sts.leave();
232 double cleanup_end_sec = os::elapsedTime();
233 if (PrintGC) {
234 gclog_or_tty->date_stamp(PrintGCDateStamps);
235 gclog_or_tty->stamp(PrintGCTimeStamps);
236 gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]",
237 cleanup_end_sec - cleanup_start_sec);
238 }
239 }
240 guarantee(cm()->cleanup_list_is_empty(),
241 "at this point there should be no regions on the cleanup list");
243 if (cm()->has_aborted()) {
244 if (PrintGC) {
245 gclog_or_tty->date_stamp(PrintGCDateStamps);
246 gclog_or_tty->stamp(PrintGCTimeStamps);
247 gclog_or_tty->print_cr("[GC concurrent-mark-abort]");
248 }
249 }
251 // we now want to allow clearing of the marking bitmap to be
252 // suspended by a collection pause.
253 _sts.join();
254 _cm->clearNextBitmap();
255 _sts.leave();
256 }
258 // Update the number of full collections that have been
259 // completed. This will also notify the FullGCCount_lock in case a
260 // Java thread is waiting for a full GC to happen (e.g., it
261 // called System.gc() with +ExplicitGCInvokesConcurrent).
262 _sts.join();
263 g1h->increment_full_collections_completed(true /* concurrent */);
264 _sts.leave();
265 }
266 assert(_should_terminate, "just checking");
268 terminate();
269 }
272 void ConcurrentMarkThread::yield() {
273 _sts.yield("Concurrent Mark");
274 }
276 void ConcurrentMarkThread::stop() {
277 // it is ok to take late safepoints here, if needed
278 MutexLockerEx mu(Terminator_lock);
279 _should_terminate = true;
280 while (!_has_terminated) {
281 Terminator_lock->wait();
282 }
283 }
285 void ConcurrentMarkThread::print() const {
286 print_on(tty);
287 }
289 void ConcurrentMarkThread::print_on(outputStream* st) const {
290 st->print("\"G1 Main Concurrent Mark GC Thread\" ");
291 Thread::print_on(st);
292 st->cr();
293 }
295 void ConcurrentMarkThread::sleepBeforeNextCycle() {
296 // We join here because we don't want to do the "shouldConcurrentMark()"
297 // below while the world is otherwise stopped.
298 assert(!in_progress(), "should have been cleared");
300 MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
301 while (!started()) {
302 CGC_lock->wait(Mutex::_no_safepoint_check_flag);
303 }
304 set_in_progress();
305 clear_started();
306 }
308 // Note: this method, although exported by the ConcurrentMarkSweepThread,
309 // which is a non-JavaThread, can only be called by a JavaThread.
310 // Currently this is done at vm creation time (post-vm-init) by the
311 // main/Primordial (Java)Thread.
312 // XXX Consider changing this in the future to allow the CMS thread
313 // itself to create this thread?
314 void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
315 assert(_slt == NULL, "SLT already created");
316 _slt = SurrogateLockerThread::make(THREAD);
317 }