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

Thu, 22 Sep 2011 10:57:37 -0700

author
johnc
date
Thu, 22 Sep 2011 10:57:37 -0700
changeset 3175
4dfb2df418f2
parent 3114
20213c8a3c40
child 3218
db89aa49298f
permissions
-rw-r--r--

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

ysr@777 1 /*
trims@2708 2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 27 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
stefank@2314 28 #include "gc_implementation/g1/vm_operations_g1.hpp"
stefank@2314 29 #include "gc_implementation/shared/isGCActiveMark.hpp"
tonyp@2315 30 #include "gc_implementation/g1/vm_operations_g1.hpp"
stefank@2314 31 #include "runtime/interfaceSupport.hpp"
ysr@777 32
tonyp@2315 33 VM_G1CollectForAllocation::VM_G1CollectForAllocation(
tonyp@2315 34 unsigned int gc_count_before,
tonyp@2315 35 size_t word_size)
tonyp@2315 36 : VM_G1OperationWithAllocRequest(gc_count_before, word_size) {
tonyp@2315 37 guarantee(word_size > 0, "an allocation should always be requested");
tonyp@2315 38 }
tonyp@2315 39
ysr@777 40 void VM_G1CollectForAllocation::doit() {
ysr@777 41 G1CollectedHeap* g1h = G1CollectedHeap::heap();
tonyp@2315 42 _result = g1h->satisfy_failed_allocation(_word_size, &_pause_succeeded);
tonyp@2315 43 assert(_result == NULL || _pause_succeeded,
tonyp@2315 44 "if we get back a result, the pause should have succeeded");
ysr@777 45 }
ysr@777 46
ysr@777 47 void VM_G1CollectFull::doit() {
ysr@777 48 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 49 GCCauseSetter x(g1h, _gc_cause);
ysr@777 50 g1h->do_full_collection(false /* clear_all_soft_refs */);
ysr@777 51 }
ysr@777 52
tonyp@2315 53 VM_G1IncCollectionPause::VM_G1IncCollectionPause(
tonyp@2315 54 unsigned int gc_count_before,
tonyp@2315 55 size_t word_size,
tonyp@2315 56 bool should_initiate_conc_mark,
tonyp@2315 57 double target_pause_time_ms,
tonyp@2315 58 GCCause::Cause gc_cause)
tonyp@2315 59 : VM_G1OperationWithAllocRequest(gc_count_before, word_size),
tonyp@2315 60 _should_initiate_conc_mark(should_initiate_conc_mark),
tonyp@2315 61 _target_pause_time_ms(target_pause_time_ms),
tonyp@2315 62 _full_collections_completed_before(0) {
tonyp@2315 63 guarantee(target_pause_time_ms > 0.0,
tonyp@2315 64 err_msg("target_pause_time_ms = %1.6lf should be positive",
tonyp@2315 65 target_pause_time_ms));
tonyp@2315 66 guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause,
tonyp@2315 67 "we can only request an allocation if the GC cause is for "
tonyp@2315 68 "an incremental GC pause");
tonyp@2315 69 _gc_cause = gc_cause;
tonyp@2315 70 }
tonyp@2315 71
ysr@777 72 void VM_G1IncCollectionPause::doit() {
ysr@777 73 G1CollectedHeap* g1h = G1CollectedHeap::heap();
tonyp@2011 74 assert(!_should_initiate_conc_mark ||
tonyp@2011 75 ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
tonyp@2011 76 (_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)),
tonyp@2011 77 "only a GC locker or a System.gc() induced GC should start a cycle");
tonyp@2011 78
tonyp@2315 79 if (_word_size > 0) {
tonyp@2315 80 // An allocation has been requested. So, try to do that first.
tonyp@2315 81 _result = g1h->attempt_allocation_at_safepoint(_word_size,
tonyp@2315 82 false /* expect_null_cur_alloc_region */);
tonyp@2315 83 if (_result != NULL) {
tonyp@2315 84 // If we can successfully allocate before we actually do the
tonyp@2315 85 // pause then we will consider this pause successful.
tonyp@2315 86 _pause_succeeded = true;
tonyp@2315 87 return;
tonyp@2315 88 }
tonyp@2315 89 }
tonyp@2315 90
ysr@1523 91 GCCauseSetter x(g1h, _gc_cause);
tonyp@2011 92 if (_should_initiate_conc_mark) {
tonyp@2011 93 // It's safer to read full_collections_completed() here, given
tonyp@2011 94 // that noone else will be updating it concurrently. Since we'll
tonyp@2011 95 // only need it if we're initiating a marking cycle, no point in
tonyp@2011 96 // setting it earlier.
tonyp@2011 97 _full_collections_completed_before = g1h->full_collections_completed();
tonyp@2011 98
tonyp@2011 99 // At this point we are supposed to start a concurrent cycle. We
tonyp@2011 100 // will do so if one is not already in progress.
tonyp@3114 101 bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(_gc_cause);
johnc@2970 102
johnc@2970 103 // The above routine returns true if we were able to force the
johnc@2970 104 // next GC pause to be an initial mark; it returns false if a
johnc@2970 105 // marking cycle is already in progress.
johnc@2970 106 //
johnc@2970 107 // If a marking cycle is already in progress just return and skip
johnc@2970 108 // the pause - the requesting thread should block in doit_epilogue
johnc@2970 109 // until the marking cycle is complete.
johnc@2970 110 if (!res) {
johnc@2970 111 assert(_word_size == 0, "ExplicitGCInvokesConcurrent shouldn't be allocating");
johnc@2970 112 return;
johnc@2970 113 }
tonyp@2011 114 }
tonyp@2315 115
tonyp@2315 116 _pause_succeeded =
tonyp@2315 117 g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
tonyp@2315 118 if (_pause_succeeded && _word_size > 0) {
tonyp@2315 119 // An allocation had been requested.
tonyp@2315 120 _result = g1h->attempt_allocation_at_safepoint(_word_size,
tonyp@2315 121 true /* expect_null_cur_alloc_region */);
tonyp@2315 122 } else {
tonyp@2315 123 assert(_result == NULL, "invariant");
tonyp@2315 124 }
tonyp@2011 125 }
tonyp@2011 126
tonyp@2011 127 void VM_G1IncCollectionPause::doit_epilogue() {
tonyp@2011 128 VM_GC_Operation::doit_epilogue();
tonyp@2011 129
tonyp@2011 130 // If the pause was initiated by a System.gc() and
tonyp@2011 131 // +ExplicitGCInvokesConcurrent, we have to wait here for the cycle
tonyp@2011 132 // that just started (or maybe one that was already in progress) to
tonyp@2011 133 // finish.
tonyp@2011 134 if (_gc_cause == GCCause::_java_lang_system_gc &&
tonyp@2011 135 _should_initiate_conc_mark) {
tonyp@2011 136 assert(ExplicitGCInvokesConcurrent,
tonyp@2011 137 "the only way to be here is if ExplicitGCInvokesConcurrent is set");
tonyp@2011 138
tonyp@2011 139 G1CollectedHeap* g1h = G1CollectedHeap::heap();
tonyp@2011 140
tonyp@2011 141 // In the doit() method we saved g1h->full_collections_completed()
tonyp@2011 142 // in the _full_collections_completed_before field. We have to
tonyp@2011 143 // wait until we observe that g1h->full_collections_completed()
tonyp@2011 144 // has increased by at least one. This can happen if a) we started
tonyp@2011 145 // a cycle and it completes, b) a cycle already in progress
tonyp@2011 146 // completes, or c) a Full GC happens.
tonyp@2011 147
tonyp@2011 148 // If the condition has already been reached, there's no point in
tonyp@2011 149 // actually taking the lock and doing the wait.
tonyp@2011 150 if (g1h->full_collections_completed() <=
tonyp@2011 151 _full_collections_completed_before) {
tonyp@2011 152 // The following is largely copied from CMS
tonyp@2011 153
tonyp@2011 154 Thread* thr = Thread::current();
tonyp@2011 155 assert(thr->is_Java_thread(), "invariant");
tonyp@2011 156 JavaThread* jt = (JavaThread*)thr;
tonyp@2011 157 ThreadToNativeFromVM native(jt);
tonyp@2011 158
tonyp@2011 159 MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
tonyp@2011 160 while (g1h->full_collections_completed() <=
tonyp@2011 161 _full_collections_completed_before) {
tonyp@2011 162 FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag);
tonyp@2011 163 }
tonyp@2011 164 }
tonyp@2011 165 }
ysr@777 166 }
ysr@777 167
ysr@777 168 void VM_CGC_Operation::doit() {
ysr@777 169 gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
ysr@777 170 TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
ysr@777 171 TraceTime t(_printGCMessage, PrintGC, true, gclog_or_tty);
ysr@777 172 SharedHeap* sh = SharedHeap::heap();
ysr@777 173 // This could go away if CollectedHeap gave access to _gc_is_active...
ysr@777 174 if (sh != NULL) {
ysr@777 175 IsGCActiveMark x;
ysr@777 176 _cl->do_void();
ysr@777 177 } else {
ysr@777 178 _cl->do_void();
ysr@777 179 }
ysr@777 180 }
ysr@777 181
ysr@777 182 bool VM_CGC_Operation::doit_prologue() {
ysr@777 183 Heap_lock->lock();
ysr@777 184 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true;
ysr@777 185 return true;
ysr@777 186 }
ysr@777 187
ysr@777 188 void VM_CGC_Operation::doit_epilogue() {
ysr@777 189 SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false;
ysr@777 190 Heap_lock->unlock();
ysr@777 191 }

mercurial