comparison src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @ 2030:fb712ff22571

7000559: G1: assertion failure !outer || (full_collections_started == _full_collections_completed + 1) Summary: The concurrent marking thread can complete its operation and increment the full GC counter during a Full GC. This causes the nesting of increments to the start and end of Full GCs that we are expecting to be wrong. the fix is for the marking thread to join the suspendible thread set before incrementing the counter so that it's blocked until the Full GC (or any other safepoint) is finished. The change also includes some minor code cleanup (I renamed a parameter). Reviewed-by: brutisso, ysr
author tonyp
date Tue, 14 Dec 2010 16:19:44 -0500
parents 8df09fb45352
children b03260081e9b
comparison
equal deleted inserted replaced
1996:f0ef5f5a460f 2030:fb712ff22571
1387 assert( check_young_list_empty(true /* check_heap */), 1387 assert( check_young_list_empty(true /* check_heap */),
1388 "young list should be empty at this point"); 1388 "young list should be empty at this point");
1389 } 1389 }
1390 1390
1391 // Update the number of full collections that have been completed. 1391 // Update the number of full collections that have been completed.
1392 increment_full_collections_completed(false /* outer */); 1392 increment_full_collections_completed(false /* concurrent */);
1393 1393
1394 if (PrintHeapAtGC) { 1394 if (PrintHeapAtGC) {
1395 Universe::print_heap_after_gc(); 1395 Universe::print_heap_after_gc();
1396 } 1396 }
1397 1397
2174 return 2174 return
2175 ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || 2175 ((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
2176 (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)); 2176 (cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent));
2177 } 2177 }
2178 2178
2179 void G1CollectedHeap::increment_full_collections_completed(bool outer) { 2179 void G1CollectedHeap::increment_full_collections_completed(bool concurrent) {
2180 MonitorLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); 2180 MonitorLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
2181
2182 // We assume that if concurrent == true, then the caller is a
2183 // concurrent thread that was joined the Suspendible Thread
2184 // Set. If there's ever a cheap way to check this, we should add an
2185 // assert here.
2181 2186
2182 // We have already incremented _total_full_collections at the start 2187 // We have already incremented _total_full_collections at the start
2183 // of the GC, so total_full_collections() represents how many full 2188 // of the GC, so total_full_collections() represents how many full
2184 // collections have been started. 2189 // collections have been started.
2185 unsigned int full_collections_started = total_full_collections(); 2190 unsigned int full_collections_started = total_full_collections();
2190 // completed should be either one (in the case where there was no 2195 // completed should be either one (in the case where there was no
2191 // nesting) or two (when a Full GC interrupted a concurrent cycle) 2196 // nesting) or two (when a Full GC interrupted a concurrent cycle)
2192 // behind the number of full collections started. 2197 // behind the number of full collections started.
2193 2198
2194 // This is the case for the inner caller, i.e. a Full GC. 2199 // This is the case for the inner caller, i.e. a Full GC.
2195 assert(outer || 2200 assert(concurrent ||
2196 (full_collections_started == _full_collections_completed + 1) || 2201 (full_collections_started == _full_collections_completed + 1) ||
2197 (full_collections_started == _full_collections_completed + 2), 2202 (full_collections_started == _full_collections_completed + 2),
2198 err_msg("for inner caller: full_collections_started = %u " 2203 err_msg("for inner caller (Full GC): full_collections_started = %u "
2199 "is inconsistent with _full_collections_completed = %u", 2204 "is inconsistent with _full_collections_completed = %u",
2200 full_collections_started, _full_collections_completed)); 2205 full_collections_started, _full_collections_completed));
2201 2206
2202 // This is the case for the outer caller, i.e. the concurrent cycle. 2207 // This is the case for the outer caller, i.e. the concurrent cycle.
2203 assert(!outer || 2208 assert(!concurrent ||
2204 (full_collections_started == _full_collections_completed + 1), 2209 (full_collections_started == _full_collections_completed + 1),
2205 err_msg("for outer caller: full_collections_started = %u " 2210 err_msg("for outer caller (concurrent cycle): "
2211 "full_collections_started = %u "
2206 "is inconsistent with _full_collections_completed = %u", 2212 "is inconsistent with _full_collections_completed = %u",
2207 full_collections_started, _full_collections_completed)); 2213 full_collections_started, _full_collections_completed));
2208 2214
2209 _full_collections_completed += 1; 2215 _full_collections_completed += 1;
2210 2216
2211 // We need to clear the "in_progress" flag in the CM thread before 2217 // We need to clear the "in_progress" flag in the CM thread before
2212 // we wake up any waiters (especially when ExplicitInvokesConcurrent 2218 // we wake up any waiters (especially when ExplicitInvokesConcurrent
2213 // is set) so that if a waiter requests another System.gc() it doesn't 2219 // is set) so that if a waiter requests another System.gc() it doesn't
2214 // incorrectly see that a marking cyle is still in progress. 2220 // incorrectly see that a marking cyle is still in progress.
2215 if (outer) { 2221 if (concurrent) {
2216 _cmThread->clear_in_progress(); 2222 _cmThread->clear_in_progress();
2217 } 2223 }
2218 2224
2219 // This notify_all() will ensure that a thread that called 2225 // This notify_all() will ensure that a thread that called
2220 // System.gc() with (with ExplicitGCInvokesConcurrent set or not) 2226 // System.gc() with (with ExplicitGCInvokesConcurrent set or not)