mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8064702: Remove the CMS foreground collector
Reviewed-by: kbarrett, ysr
This commit is contained in:
parent
2616e09389
commit
4b60638d85
9 changed files with 160 additions and 715 deletions
|
@ -192,7 +192,7 @@ ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(
|
||||||
FreeBlockDictionary<FreeChunk>::DictionaryChoice dictionaryChoice) :
|
FreeBlockDictionary<FreeChunk>::DictionaryChoice dictionaryChoice) :
|
||||||
CardGeneration(rs, initial_byte_size, level, ct),
|
CardGeneration(rs, initial_byte_size, level, ct),
|
||||||
_dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))),
|
_dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))),
|
||||||
_debug_collection_type(Concurrent_collection_type),
|
_debug_concurrent_cycle(true),
|
||||||
_did_compact(false)
|
_did_compact(false)
|
||||||
{
|
{
|
||||||
HeapWord* bottom = (HeapWord*) _virtual_space.low();
|
HeapWord* bottom = (HeapWord*) _virtual_space.low();
|
||||||
|
@ -612,8 +612,6 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
// Clip CMSBootstrapOccupancy between 0 and 100.
|
// Clip CMSBootstrapOccupancy between 0 and 100.
|
||||||
_bootstrap_occupancy = ((double)CMSBootstrapOccupancy)/(double)100;
|
_bootstrap_occupancy = ((double)CMSBootstrapOccupancy)/(double)100;
|
||||||
|
|
||||||
_full_gcs_since_conc_gc = 0;
|
|
||||||
|
|
||||||
// Now tell CMS generations the identity of their collector
|
// Now tell CMS generations the identity of their collector
|
||||||
ConcurrentMarkSweepGeneration::set_collector(this);
|
ConcurrentMarkSweepGeneration::set_collector(this);
|
||||||
|
|
||||||
|
@ -1248,16 +1246,10 @@ bool CMSCollector::shouldConcurrentCollect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debugging purposes, change the type of collection.
|
// For debugging purposes, change the type of collection.
|
||||||
// If the rotation is not on the concurrent collection
|
// Rotate between concurrent and stop-the-world full GCs.
|
||||||
// type, don't start a concurrent collection.
|
|
||||||
NOT_PRODUCT(
|
NOT_PRODUCT(
|
||||||
if (RotateCMSCollectionTypes &&
|
if (RotateCMSCollectionTypes) {
|
||||||
(_cmsGen->debug_collection_type() !=
|
return _cmsGen->debug_concurrent_cycle();
|
||||||
ConcurrentMarkSweepGeneration::Concurrent_collection_type)) {
|
|
||||||
assert(_cmsGen->debug_collection_type() !=
|
|
||||||
ConcurrentMarkSweepGeneration::Unknown_collection_type,
|
|
||||||
"Bad cms collection type");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1441,16 +1433,6 @@ void CMSCollector::collect(bool full,
|
||||||
size_t size,
|
size_t size,
|
||||||
bool tlab)
|
bool tlab)
|
||||||
{
|
{
|
||||||
if (!UseCMSCollectionPassing && _collectorState > Idling) {
|
|
||||||
// For debugging purposes skip the collection if the state
|
|
||||||
// is not currently idle
|
|
||||||
if (TraceCMSState) {
|
|
||||||
gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " skipped full:%d CMS state %d",
|
|
||||||
Thread::current(), full, _collectorState);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following "if" branch is present for defensive reasons.
|
// The following "if" branch is present for defensive reasons.
|
||||||
// In the current uses of this interface, it can be replaced with:
|
// In the current uses of this interface, it can be replaced with:
|
||||||
// assert(!GC_locker.is_active(), "Can't be called otherwise");
|
// assert(!GC_locker.is_active(), "Can't be called otherwise");
|
||||||
|
@ -1466,7 +1448,6 @@ void CMSCollector::collect(bool full,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
acquire_control_and_collect(full, clear_all_soft_refs);
|
acquire_control_and_collect(full, clear_all_soft_refs);
|
||||||
_full_gcs_since_conc_gc++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) {
|
void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) {
|
||||||
|
@ -1636,66 +1617,52 @@ void CMSCollector::acquire_control_and_collect(bool full,
|
||||||
gclog_or_tty->print_cr(" gets control with state %d", _collectorState);
|
gclog_or_tty->print_cr(" gets control with state %d", _collectorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we need to do a compaction, or if not, whether
|
// Inform cms gen if this was due to partial collection failing.
|
||||||
// we need to start the mark-sweep from scratch.
|
// The CMS gen may use this fact to determine its expansion policy.
|
||||||
bool should_compact = false;
|
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||||
bool should_start_over = false;
|
if (gch->incremental_collection_will_fail(false /* don't consult_young */)) {
|
||||||
decide_foreground_collection_type(clear_all_soft_refs,
|
assert(!_cmsGen->incremental_collection_failed(),
|
||||||
&should_compact, &should_start_over);
|
"Should have been noticed, reacted to and cleared");
|
||||||
|
_cmsGen->set_incremental_collection_failed();
|
||||||
NOT_PRODUCT(
|
|
||||||
if (RotateCMSCollectionTypes) {
|
|
||||||
if (_cmsGen->debug_collection_type() ==
|
|
||||||
ConcurrentMarkSweepGeneration::MSC_foreground_collection_type) {
|
|
||||||
should_compact = true;
|
|
||||||
} else if (_cmsGen->debug_collection_type() ==
|
|
||||||
ConcurrentMarkSweepGeneration::MS_foreground_collection_type) {
|
|
||||||
should_compact = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
if (first_state > Idling) {
|
if (first_state > Idling) {
|
||||||
report_concurrent_mode_interruption();
|
report_concurrent_mode_interruption();
|
||||||
}
|
}
|
||||||
|
|
||||||
set_did_compact(should_compact);
|
set_did_compact(true);
|
||||||
if (should_compact) {
|
|
||||||
// If the collection is being acquired from the background
|
|
||||||
// collector, there may be references on the discovered
|
|
||||||
// references lists that have NULL referents (being those
|
|
||||||
// that were concurrently cleared by a mutator) or
|
|
||||||
// that are no longer active (having been enqueued concurrently
|
|
||||||
// by the mutator).
|
|
||||||
// Scrub the list of those references because Mark-Sweep-Compact
|
|
||||||
// code assumes referents are not NULL and that all discovered
|
|
||||||
// Reference objects are active.
|
|
||||||
ref_processor()->clean_up_discovered_references();
|
|
||||||
|
|
||||||
if (first_state > Idling) {
|
// If the collection is being acquired from the background
|
||||||
save_heap_summary();
|
// collector, there may be references on the discovered
|
||||||
}
|
// references lists that have NULL referents (being those
|
||||||
|
// that were concurrently cleared by a mutator) or
|
||||||
|
// that are no longer active (having been enqueued concurrently
|
||||||
|
// by the mutator).
|
||||||
|
// Scrub the list of those references because Mark-Sweep-Compact
|
||||||
|
// code assumes referents are not NULL and that all discovered
|
||||||
|
// Reference objects are active.
|
||||||
|
ref_processor()->clean_up_discovered_references();
|
||||||
|
|
||||||
do_compaction_work(clear_all_soft_refs);
|
if (first_state > Idling) {
|
||||||
|
save_heap_summary();
|
||||||
// Has the GC time limit been exceeded?
|
|
||||||
DefNewGeneration* young_gen = _young_gen->as_DefNewGeneration();
|
|
||||||
size_t max_eden_size = young_gen->max_capacity() -
|
|
||||||
young_gen->to()->capacity() -
|
|
||||||
young_gen->from()->capacity();
|
|
||||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
|
||||||
GCCause::Cause gc_cause = gch->gc_cause();
|
|
||||||
size_policy()->check_gc_overhead_limit(_young_gen->used(),
|
|
||||||
young_gen->eden()->used(),
|
|
||||||
_cmsGen->max_capacity(),
|
|
||||||
max_eden_size,
|
|
||||||
full,
|
|
||||||
gc_cause,
|
|
||||||
gch->collector_policy());
|
|
||||||
} else {
|
|
||||||
do_mark_sweep_work(clear_all_soft_refs, first_state,
|
|
||||||
should_start_over);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_compaction_work(clear_all_soft_refs);
|
||||||
|
|
||||||
|
// Has the GC time limit been exceeded?
|
||||||
|
DefNewGeneration* young_gen = _young_gen->as_DefNewGeneration();
|
||||||
|
size_t max_eden_size = young_gen->max_capacity() -
|
||||||
|
young_gen->to()->capacity() -
|
||||||
|
young_gen->from()->capacity();
|
||||||
|
GCCause::Cause gc_cause = gch->gc_cause();
|
||||||
|
size_policy()->check_gc_overhead_limit(_young_gen->used(),
|
||||||
|
young_gen->eden()->used(),
|
||||||
|
_cmsGen->max_capacity(),
|
||||||
|
max_eden_size,
|
||||||
|
full,
|
||||||
|
gc_cause,
|
||||||
|
gch->collector_policy());
|
||||||
|
|
||||||
// Reset the expansion cause, now that we just completed
|
// Reset the expansion cause, now that we just completed
|
||||||
// a collection cycle.
|
// a collection cycle.
|
||||||
clear_expansion_cause();
|
clear_expansion_cause();
|
||||||
|
@ -1713,68 +1680,6 @@ void CMSCollector::compute_new_size() {
|
||||||
_cmsGen->compute_new_size_free_list();
|
_cmsGen->compute_new_size_free_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
// A work method used by foreground collection to determine
|
|
||||||
// what type of collection (compacting or not, continuing or fresh)
|
|
||||||
// it should do.
|
|
||||||
// NOTE: the intent is to make UseCMSCompactAtFullCollection
|
|
||||||
// and CMSCompactWhenClearAllSoftRefs the default in the future
|
|
||||||
// and do away with the flags after a suitable period.
|
|
||||||
void CMSCollector::decide_foreground_collection_type(
|
|
||||||
bool clear_all_soft_refs, bool* should_compact,
|
|
||||||
bool* should_start_over) {
|
|
||||||
// Normally, we'll compact only if the UseCMSCompactAtFullCollection
|
|
||||||
// flag is set, and we have either requested a System.gc() or
|
|
||||||
// the number of full gc's since the last concurrent cycle
|
|
||||||
// has exceeded the threshold set by CMSFullGCsBeforeCompaction,
|
|
||||||
// or if an incremental collection has failed
|
|
||||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
|
||||||
assert(gch->collector_policy()->is_generation_policy(),
|
|
||||||
"You may want to check the correctness of the following");
|
|
||||||
// Inform cms gen if this was due to partial collection failing.
|
|
||||||
// The CMS gen may use this fact to determine its expansion policy.
|
|
||||||
if (gch->incremental_collection_will_fail(false /* don't consult_young */)) {
|
|
||||||
assert(!_cmsGen->incremental_collection_failed(),
|
|
||||||
"Should have been noticed, reacted to and cleared");
|
|
||||||
_cmsGen->set_incremental_collection_failed();
|
|
||||||
}
|
|
||||||
*should_compact =
|
|
||||||
UseCMSCompactAtFullCollection &&
|
|
||||||
((_full_gcs_since_conc_gc >= CMSFullGCsBeforeCompaction) ||
|
|
||||||
GCCause::is_user_requested_gc(gch->gc_cause()) ||
|
|
||||||
gch->incremental_collection_will_fail(true /* consult_young */));
|
|
||||||
*should_start_over = false;
|
|
||||||
if (clear_all_soft_refs && !*should_compact) {
|
|
||||||
// We are about to do a last ditch collection attempt
|
|
||||||
// so it would normally make sense to do a compaction
|
|
||||||
// to reclaim as much space as possible.
|
|
||||||
if (CMSCompactWhenClearAllSoftRefs) {
|
|
||||||
// Default: The rationale is that in this case either
|
|
||||||
// we are past the final marking phase, in which case
|
|
||||||
// we'd have to start over, or so little has been done
|
|
||||||
// that there's little point in saving that work. Compaction
|
|
||||||
// appears to be the sensible choice in either case.
|
|
||||||
*should_compact = true;
|
|
||||||
} else {
|
|
||||||
// We have been asked to clear all soft refs, but not to
|
|
||||||
// compact. Make sure that we aren't past the final checkpoint
|
|
||||||
// phase, for that is where we process soft refs. If we are already
|
|
||||||
// past that phase, we'll need to redo the refs discovery phase and
|
|
||||||
// if necessary clear soft refs that weren't previously
|
|
||||||
// cleared. We do so by remembering the phase in which
|
|
||||||
// we came in, and if we are past the refs processing
|
|
||||||
// phase, we'll choose to just redo the mark-sweep
|
|
||||||
// collection from scratch.
|
|
||||||
if (_collectorState > FinalMarking) {
|
|
||||||
// We are past the refs processing phase;
|
|
||||||
// start over and do a fresh synchronous CMS cycle
|
|
||||||
_collectorState = Resetting; // skip to reset to start new cycle
|
|
||||||
reset(false /* == !asynch */);
|
|
||||||
*should_start_over = true;
|
|
||||||
} // else we can continue a possibly ongoing current cycle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A work method used by the foreground collector to do
|
// A work method used by the foreground collector to do
|
||||||
// a mark-sweep-compact.
|
// a mark-sweep-compact.
|
||||||
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||||
|
@ -1787,10 +1692,6 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||||
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
|
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
|
||||||
|
|
||||||
GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id());
|
GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id());
|
||||||
if (PrintGC && Verbose && !(GCCause::is_user_requested_gc(gch->gc_cause()))) {
|
|
||||||
gclog_or_tty->print_cr("Compact ConcurrentMarkSweepGeneration after %d "
|
|
||||||
"collections passed to foreground collector", _full_gcs_since_conc_gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporarily widen the span of the weak reference processing to
|
// Temporarily widen the span of the weak reference processing to
|
||||||
// the entire heap.
|
// the entire heap.
|
||||||
|
@ -1852,7 +1753,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||||
_collectorState = Resetting;
|
_collectorState = Resetting;
|
||||||
assert(_restart_addr == NULL,
|
assert(_restart_addr == NULL,
|
||||||
"Should have been NULL'd before baton was passed");
|
"Should have been NULL'd before baton was passed");
|
||||||
reset(false /* == !asynch */);
|
reset(false /* == !concurrent */);
|
||||||
_cmsGen->reset_after_compaction();
|
_cmsGen->reset_after_compaction();
|
||||||
_concurrent_cycles_since_last_unload = 0;
|
_concurrent_cycles_since_last_unload = 0;
|
||||||
|
|
||||||
|
@ -1875,40 +1776,6 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||||
// in the heap's do_collection() method.
|
// in the heap's do_collection() method.
|
||||||
}
|
}
|
||||||
|
|
||||||
// A work method used by the foreground collector to do
|
|
||||||
// a mark-sweep, after taking over from a possibly on-going
|
|
||||||
// concurrent mark-sweep collection.
|
|
||||||
void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
|
|
||||||
CollectorState first_state, bool should_start_over) {
|
|
||||||
if (PrintGC && Verbose) {
|
|
||||||
gclog_or_tty->print_cr("Pass concurrent collection to foreground "
|
|
||||||
"collector with count %d",
|
|
||||||
_full_gcs_since_conc_gc);
|
|
||||||
}
|
|
||||||
switch (_collectorState) {
|
|
||||||
case Idling:
|
|
||||||
if (first_state == Idling || should_start_over) {
|
|
||||||
// The background GC was not active, or should
|
|
||||||
// restarted from scratch; start the cycle.
|
|
||||||
_collectorState = InitialMarking;
|
|
||||||
}
|
|
||||||
// If first_state was not Idling, then a background GC
|
|
||||||
// was in progress and has now finished. No need to do it
|
|
||||||
// again. Leave the state as Idling.
|
|
||||||
break;
|
|
||||||
case Precleaning:
|
|
||||||
// In the foreground case don't do the precleaning since
|
|
||||||
// it is not done concurrently and there is extra work
|
|
||||||
// required.
|
|
||||||
_collectorState = FinalMarking;
|
|
||||||
}
|
|
||||||
collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause());
|
|
||||||
|
|
||||||
// For a mark-sweep, compute_new_size() will be called
|
|
||||||
// in the heap's do_collection() method.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CMSCollector::print_eden_and_survivor_chunk_arrays() {
|
void CMSCollector::print_eden_and_survivor_chunk_arrays() {
|
||||||
DefNewGeneration* dng = _young_gen->as_DefNewGeneration();
|
DefNewGeneration* dng = _young_gen->as_DefNewGeneration();
|
||||||
ContiguousSpace* eden_space = dng->eden();
|
ContiguousSpace* eden_space = dng->eden();
|
||||||
|
@ -1989,13 +1856,7 @@ class ReleaseForegroundGC: public StackObj {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// There are separate collect_in_background and collect_in_foreground because of
|
void CMSCollector::collect_in_background(GCCause::Cause cause) {
|
||||||
// the different locking requirements of the background collector and the
|
|
||||||
// foreground collector. There was originally an attempt to share
|
|
||||||
// one "collect" method between the background collector and the foreground
|
|
||||||
// collector but the if-then-else required made it cleaner to have
|
|
||||||
// separate methods.
|
|
||||||
void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) {
|
|
||||||
assert(Thread::current()->is_ConcurrentGC_thread(),
|
assert(Thread::current()->is_ConcurrentGC_thread(),
|
||||||
"A CMS asynchronous collection is only allowed on a CMS thread.");
|
"A CMS asynchronous collection is only allowed on a CMS thread.");
|
||||||
|
|
||||||
|
@ -2036,7 +1897,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Caus
|
||||||
// Used for PrintGC
|
// Used for PrintGC
|
||||||
size_t prev_used;
|
size_t prev_used;
|
||||||
if (PrintGC && Verbose) {
|
if (PrintGC && Verbose) {
|
||||||
prev_used = _cmsGen->used(); // XXXPERM
|
prev_used = _cmsGen->used();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The change of the collection state is normally done at this level;
|
// The change of the collection state is normally done at this level;
|
||||||
|
@ -2116,7 +1977,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Caus
|
||||||
break;
|
break;
|
||||||
case Marking:
|
case Marking:
|
||||||
// initial marking in checkpointRootsInitialWork has been completed
|
// initial marking in checkpointRootsInitialWork has been completed
|
||||||
if (markFromRoots(true)) { // we were successful
|
if (markFromRoots()) { // we were successful
|
||||||
assert(_collectorState == Precleaning, "Collector state should "
|
assert(_collectorState == Precleaning, "Collector state should "
|
||||||
"have changed");
|
"have changed");
|
||||||
} else {
|
} else {
|
||||||
|
@ -2146,10 +2007,9 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Caus
|
||||||
break;
|
break;
|
||||||
case Sweeping:
|
case Sweeping:
|
||||||
// final marking in checkpointRootsFinal has been completed
|
// final marking in checkpointRootsFinal has been completed
|
||||||
sweep(true);
|
sweep();
|
||||||
assert(_collectorState == Resizing, "Collector state change "
|
assert(_collectorState == Resizing, "Collector state change "
|
||||||
"to Resizing must be done under the free_list_lock");
|
"to Resizing must be done under the free_list_lock");
|
||||||
_full_gcs_since_conc_gc = 0;
|
|
||||||
|
|
||||||
case Resizing: {
|
case Resizing: {
|
||||||
// Sweeping has been completed...
|
// Sweeping has been completed...
|
||||||
|
@ -2222,12 +2082,6 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Caus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::register_foreground_gc_start(GCCause::Cause cause) {
|
|
||||||
if (!_cms_start_registered) {
|
|
||||||
register_gc_start(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMSCollector::register_gc_start(GCCause::Cause cause) {
|
void CMSCollector::register_gc_start(GCCause::Cause cause) {
|
||||||
_cms_start_registered = true;
|
_cms_start_registered = true;
|
||||||
_gc_timer_cm->register_gc_start();
|
_gc_timer_cm->register_gc_start();
|
||||||
|
@ -2255,120 +2109,6 @@ void CMSCollector::report_heap_summary(GCWhen::Type when) {
|
||||||
_gc_tracer_cm->report_metaspace_summary(when, _last_metaspace_summary);
|
_gc_tracer_cm->report_metaspace_summary(when, _last_metaspace_summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {
|
|
||||||
assert(_foregroundGCIsActive && !_foregroundGCShouldWait,
|
|
||||||
"Foreground collector should be waiting, not executing");
|
|
||||||
assert(Thread::current()->is_VM_thread(), "A foreground collection"
|
|
||||||
"may only be done by the VM Thread with the world stopped");
|
|
||||||
assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
|
|
||||||
"VM thread should have CMS token");
|
|
||||||
|
|
||||||
// The gc id is created in register_foreground_gc_start if this collection is synchronous
|
|
||||||
const GCId gc_id = _collectorState == InitialMarking ? GCId::peek() : _gc_tracer_cm->gc_id();
|
|
||||||
NOT_PRODUCT(GCTraceTime t("CMS:MS (foreground) ", PrintGCDetails && Verbose,
|
|
||||||
true, NULL, gc_id);)
|
|
||||||
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact);
|
|
||||||
|
|
||||||
HandleMark hm; // Discard invalid handles created during verification
|
|
||||||
|
|
||||||
if (VerifyBeforeGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot the soft reference policy to be used in this collection cycle.
|
|
||||||
ref_processor()->setup_policy(clear_all_soft_refs);
|
|
||||||
|
|
||||||
// Decide if class unloading should be done
|
|
||||||
update_should_unload_classes();
|
|
||||||
|
|
||||||
bool init_mark_was_synchronous = false; // until proven otherwise
|
|
||||||
while (_collectorState != Idling) {
|
|
||||||
if (TraceCMSState) {
|
|
||||||
gclog_or_tty->print_cr("Thread " INTPTR_FORMAT " in CMS state %d",
|
|
||||||
Thread::current(), _collectorState);
|
|
||||||
}
|
|
||||||
switch (_collectorState) {
|
|
||||||
case InitialMarking:
|
|
||||||
register_foreground_gc_start(cause);
|
|
||||||
init_mark_was_synchronous = true; // fact to be exploited in re-mark
|
|
||||||
checkpointRootsInitial(false);
|
|
||||||
assert(_collectorState == Marking, "Collector state should have changed"
|
|
||||||
" within checkpointRootsInitial()");
|
|
||||||
break;
|
|
||||||
case Marking:
|
|
||||||
// initial marking in checkpointRootsInitialWork has been completed
|
|
||||||
if (VerifyDuringGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify("Verify before initial mark: ");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bool res = markFromRoots(false);
|
|
||||||
assert(res && _collectorState == FinalMarking, "Collector state should "
|
|
||||||
"have changed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FinalMarking:
|
|
||||||
if (VerifyDuringGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify("Verify before re-mark: ");
|
|
||||||
}
|
|
||||||
checkpointRootsFinal(false, clear_all_soft_refs,
|
|
||||||
init_mark_was_synchronous);
|
|
||||||
assert(_collectorState == Sweeping, "Collector state should not "
|
|
||||||
"have changed within checkpointRootsFinal()");
|
|
||||||
break;
|
|
||||||
case Sweeping:
|
|
||||||
// final marking in checkpointRootsFinal has been completed
|
|
||||||
if (VerifyDuringGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify("Verify before sweep: ");
|
|
||||||
}
|
|
||||||
sweep(false);
|
|
||||||
assert(_collectorState == Resizing, "Incorrect state");
|
|
||||||
break;
|
|
||||||
case Resizing: {
|
|
||||||
// Sweeping has been completed; the actual resize in this case
|
|
||||||
// is done separately; nothing to be done in this state.
|
|
||||||
_collectorState = Resetting;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Resetting:
|
|
||||||
// The heap has been resized.
|
|
||||||
if (VerifyDuringGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify("Verify before reset: ");
|
|
||||||
}
|
|
||||||
save_heap_summary();
|
|
||||||
reset(false);
|
|
||||||
assert(_collectorState == Idling, "Collector state should "
|
|
||||||
"have changed");
|
|
||||||
break;
|
|
||||||
case Precleaning:
|
|
||||||
case AbortablePreclean:
|
|
||||||
// Elide the preclean phase
|
|
||||||
_collectorState = FinalMarking;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
if (TraceCMSState) {
|
|
||||||
gclog_or_tty->print_cr(" Thread " INTPTR_FORMAT " done - next CMS state %d",
|
|
||||||
Thread::current(), _collectorState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VerifyAfterGC &&
|
|
||||||
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
|
|
||||||
Universe::verify();
|
|
||||||
}
|
|
||||||
if (TraceCMSState) {
|
|
||||||
gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT
|
|
||||||
" exiting collection CMS state %d",
|
|
||||||
Thread::current(), _collectorState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMSCollector::waitForForegroundGC() {
|
bool CMSCollector::waitForForegroundGC() {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
|
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
|
||||||
|
@ -3345,7 +3085,7 @@ class CMSParInitialMarkTask: public CMSParMarkTask {
|
||||||
// Checkpoint the roots into this generation from outside
|
// Checkpoint the roots into this generation from outside
|
||||||
// this generation. [Note this initial checkpoint need only
|
// this generation. [Note this initial checkpoint need only
|
||||||
// be approximate -- we'll do a catch up phase subsequently.]
|
// be approximate -- we'll do a catch up phase subsequently.]
|
||||||
void CMSCollector::checkpointRootsInitial(bool asynch) {
|
void CMSCollector::checkpointRootsInitial() {
|
||||||
assert(_collectorState == InitialMarking, "Wrong collector state");
|
assert(_collectorState == InitialMarking, "Wrong collector state");
|
||||||
check_correct_thread_executing();
|
check_correct_thread_executing();
|
||||||
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
|
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
|
||||||
|
@ -3356,32 +3096,19 @@ void CMSCollector::checkpointRootsInitial(bool asynch) {
|
||||||
ReferenceProcessor* rp = ref_processor();
|
ReferenceProcessor* rp = ref_processor();
|
||||||
SpecializationStats::clear();
|
SpecializationStats::clear();
|
||||||
assert(_restart_addr == NULL, "Control point invariant");
|
assert(_restart_addr == NULL, "Control point invariant");
|
||||||
if (asynch) {
|
{
|
||||||
// acquire locks for subsequent manipulations
|
// acquire locks for subsequent manipulations
|
||||||
MutexLockerEx x(bitMapLock(),
|
MutexLockerEx x(bitMapLock(),
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
checkpointRootsInitialWork(asynch);
|
checkpointRootsInitialWork();
|
||||||
// enable ("weak") refs discovery
|
// enable ("weak") refs discovery
|
||||||
rp->enable_discovery(true /*verify_disabled*/, true /*check_no_refs*/);
|
rp->enable_discovery(true /*verify_disabled*/, true /*check_no_refs*/);
|
||||||
_collectorState = Marking;
|
_collectorState = Marking;
|
||||||
} else {
|
|
||||||
// (Weak) Refs discovery: this is controlled from genCollectedHeap::do_collection
|
|
||||||
// which recognizes if we are a CMS generation, and doesn't try to turn on
|
|
||||||
// discovery; verify that they aren't meddling.
|
|
||||||
assert(!rp->discovery_is_atomic(),
|
|
||||||
"incorrect setting of discovery predicate");
|
|
||||||
assert(!rp->discovery_enabled(), "genCollectedHeap shouldn't control "
|
|
||||||
"ref discovery for this generation kind");
|
|
||||||
// already have locks
|
|
||||||
checkpointRootsInitialWork(asynch);
|
|
||||||
// now enable ("weak") refs discovery
|
|
||||||
rp->enable_discovery(true /*verify_disabled*/, false /*verify_no_refs*/);
|
|
||||||
_collectorState = Marking;
|
|
||||||
}
|
}
|
||||||
SpecializationStats::print();
|
SpecializationStats::print();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::checkpointRootsInitialWork(bool asynch) {
|
void CMSCollector::checkpointRootsInitialWork() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped");
|
assert(SafepointSynchronize::is_at_safepoint(), "world should be stopped");
|
||||||
assert(_collectorState == InitialMarking, "just checking");
|
assert(_collectorState == InitialMarking, "just checking");
|
||||||
|
|
||||||
|
@ -3483,9 +3210,9 @@ void CMSCollector::checkpointRootsInitialWork(bool asynch) {
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSCollector::markFromRoots(bool asynch) {
|
bool CMSCollector::markFromRoots() {
|
||||||
// we might be tempted to assert that:
|
// we might be tempted to assert that:
|
||||||
// assert(asynch == !SafepointSynchronize::is_at_safepoint(),
|
// assert(!SafepointSynchronize::is_at_safepoint(),
|
||||||
// "inconsistent argument?");
|
// "inconsistent argument?");
|
||||||
// However that wouldn't be right, because it's possible that
|
// However that wouldn't be right, because it's possible that
|
||||||
// a safepoint is indeed in progress as a younger generation
|
// a safepoint is indeed in progress as a younger generation
|
||||||
|
@ -3494,37 +3221,28 @@ bool CMSCollector::markFromRoots(bool asynch) {
|
||||||
check_correct_thread_executing();
|
check_correct_thread_executing();
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
|
|
||||||
bool res;
|
// Weak ref discovery note: We may be discovering weak
|
||||||
if (asynch) {
|
// refs in this generation concurrent (but interleaved) with
|
||||||
// Weak ref discovery note: We may be discovering weak
|
// weak ref discovery by a younger generation collector.
|
||||||
// refs in this generation concurrent (but interleaved) with
|
|
||||||
// weak ref discovery by a younger generation collector.
|
|
||||||
|
|
||||||
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
||||||
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
|
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
|
||||||
CMSPhaseAccounting pa(this, "mark", _gc_tracer_cm->gc_id(), !PrintGCDetails);
|
CMSPhaseAccounting pa(this, "mark", _gc_tracer_cm->gc_id(), !PrintGCDetails);
|
||||||
res = markFromRootsWork(asynch);
|
bool res = markFromRootsWork();
|
||||||
if (res) {
|
if (res) {
|
||||||
_collectorState = Precleaning;
|
_collectorState = Precleaning;
|
||||||
} else { // We failed and a foreground collection wants to take over
|
} else { // We failed and a foreground collection wants to take over
|
||||||
assert(_foregroundGCIsActive, "internal state inconsistency");
|
assert(_foregroundGCIsActive, "internal state inconsistency");
|
||||||
assert(_restart_addr == NULL, "foreground will restart from scratch");
|
assert(_restart_addr == NULL, "foreground will restart from scratch");
|
||||||
if (PrintGCDetails) {
|
if (PrintGCDetails) {
|
||||||
gclog_or_tty->print_cr("bailing out to foreground collection");
|
gclog_or_tty->print_cr("bailing out to foreground collection");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(),
|
|
||||||
"inconsistent with asynch == false");
|
|
||||||
// already have locks
|
|
||||||
res = markFromRootsWork(asynch);
|
|
||||||
_collectorState = FinalMarking;
|
|
||||||
}
|
}
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSCollector::markFromRootsWork(bool asynch) {
|
bool CMSCollector::markFromRootsWork() {
|
||||||
// iterate over marked bits in bit map, doing a full scan and mark
|
// iterate over marked bits in bit map, doing a full scan and mark
|
||||||
// from these roots using the following algorithm:
|
// from these roots using the following algorithm:
|
||||||
// . if oop is to the right of the current scan pointer,
|
// . if oop is to the right of the current scan pointer,
|
||||||
|
@ -3549,9 +3267,9 @@ bool CMSCollector::markFromRootsWork(bool asynch) {
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (CMSConcurrentMTEnabled && ConcGCThreads > 0) {
|
if (CMSConcurrentMTEnabled && ConcGCThreads > 0) {
|
||||||
result = do_marking_mt(asynch);
|
result = do_marking_mt();
|
||||||
} else {
|
} else {
|
||||||
result = do_marking_st(asynch);
|
result = do_marking_st();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -3591,7 +3309,6 @@ class CMSConcMarkingTerminatorTerminator: public TerminatorTerminator {
|
||||||
class CMSConcMarkingTask: public YieldingFlexibleGangTask {
|
class CMSConcMarkingTask: public YieldingFlexibleGangTask {
|
||||||
CMSCollector* _collector;
|
CMSCollector* _collector;
|
||||||
int _n_workers; // requested/desired # workers
|
int _n_workers; // requested/desired # workers
|
||||||
bool _asynch;
|
|
||||||
bool _result;
|
bool _result;
|
||||||
CompactibleFreeListSpace* _cms_space;
|
CompactibleFreeListSpace* _cms_space;
|
||||||
char _pad_front[64]; // padding to ...
|
char _pad_front[64]; // padding to ...
|
||||||
|
@ -3612,13 +3329,12 @@ class CMSConcMarkingTask: public YieldingFlexibleGangTask {
|
||||||
public:
|
public:
|
||||||
CMSConcMarkingTask(CMSCollector* collector,
|
CMSConcMarkingTask(CMSCollector* collector,
|
||||||
CompactibleFreeListSpace* cms_space,
|
CompactibleFreeListSpace* cms_space,
|
||||||
bool asynch,
|
|
||||||
YieldingFlexibleWorkGang* workers,
|
YieldingFlexibleWorkGang* workers,
|
||||||
OopTaskQueueSet* task_queues):
|
OopTaskQueueSet* task_queues):
|
||||||
YieldingFlexibleGangTask("Concurrent marking done multi-threaded"),
|
YieldingFlexibleGangTask("Concurrent marking done multi-threaded"),
|
||||||
_collector(collector),
|
_collector(collector),
|
||||||
_cms_space(cms_space),
|
_cms_space(cms_space),
|
||||||
_asynch(asynch), _n_workers(0), _result(true),
|
_n_workers(0), _result(true),
|
||||||
_task_queues(task_queues),
|
_task_queues(task_queues),
|
||||||
_term(_n_workers, task_queues, _collector),
|
_term(_n_workers, task_queues, _collector),
|
||||||
_bit_map_lock(collector->bitMapLock())
|
_bit_map_lock(collector->bitMapLock())
|
||||||
|
@ -3645,8 +3361,7 @@ class CMSConcMarkingTask: public YieldingFlexibleGangTask {
|
||||||
void work(uint worker_id);
|
void work(uint worker_id);
|
||||||
bool should_yield() {
|
bool should_yield() {
|
||||||
return ConcurrentMarkSweepThread::should_yield()
|
return ConcurrentMarkSweepThread::should_yield()
|
||||||
&& !_collector->foregroundGCIsActive()
|
&& !_collector->foregroundGCIsActive();
|
||||||
&& _asynch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void coordinator_yield(); // stuff done by coordinator
|
virtual void coordinator_yield(); // stuff done by coordinator
|
||||||
|
@ -3878,8 +3593,7 @@ void CMSConcMarkingTask::do_scan_and_mark(int i, CompactibleFreeListSpace* sp) {
|
||||||
Par_MarkFromRootsClosure cl(this, _collector, my_span,
|
Par_MarkFromRootsClosure cl(this, _collector, my_span,
|
||||||
&_collector->_markBitMap,
|
&_collector->_markBitMap,
|
||||||
work_queue(i),
|
work_queue(i),
|
||||||
&_collector->_markStack,
|
&_collector->_markStack);
|
||||||
_asynch);
|
|
||||||
_collector->_markBitMap.iterate(&cl, my_span.start(), my_span.end());
|
_collector->_markBitMap.iterate(&cl, my_span.start(), my_span.end());
|
||||||
} // else nothing to do for this task
|
} // else nothing to do for this task
|
||||||
} // else nothing to do for this task
|
} // else nothing to do for this task
|
||||||
|
@ -4084,7 +3798,7 @@ void CMSConcMarkingTask::coordinator_yield() {
|
||||||
_collector->startTimer();
|
_collector->startTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSCollector::do_marking_mt(bool asynch) {
|
bool CMSCollector::do_marking_mt() {
|
||||||
assert(ConcGCThreads > 0 && conc_workers() != NULL, "precondition");
|
assert(ConcGCThreads > 0 && conc_workers() != NULL, "precondition");
|
||||||
int num_workers = AdaptiveSizePolicy::calc_active_conc_workers(
|
int num_workers = AdaptiveSizePolicy::calc_active_conc_workers(
|
||||||
conc_workers()->total_workers(),
|
conc_workers()->total_workers(),
|
||||||
|
@ -4096,7 +3810,6 @@ bool CMSCollector::do_marking_mt(bool asynch) {
|
||||||
|
|
||||||
CMSConcMarkingTask tsk(this,
|
CMSConcMarkingTask tsk(this,
|
||||||
cms_space,
|
cms_space,
|
||||||
asynch,
|
|
||||||
conc_workers(),
|
conc_workers(),
|
||||||
task_queues());
|
task_queues());
|
||||||
|
|
||||||
|
@ -4125,7 +3838,7 @@ bool CMSCollector::do_marking_mt(bool asynch) {
|
||||||
// If _restart_addr is non-NULL, a marking stack overflow
|
// If _restart_addr is non-NULL, a marking stack overflow
|
||||||
// occurred; we need to do a fresh marking iteration from the
|
// occurred; we need to do a fresh marking iteration from the
|
||||||
// indicated restart address.
|
// indicated restart address.
|
||||||
if (_foregroundGCIsActive && asynch) {
|
if (_foregroundGCIsActive) {
|
||||||
// We may be running into repeated stack overflows, having
|
// We may be running into repeated stack overflows, having
|
||||||
// reached the limit of the stack size, while making very
|
// reached the limit of the stack size, while making very
|
||||||
// slow forward progress. It may be best to bail out and
|
// slow forward progress. It may be best to bail out and
|
||||||
|
@ -4154,14 +3867,14 @@ bool CMSCollector::do_marking_mt(bool asynch) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSCollector::do_marking_st(bool asynch) {
|
bool CMSCollector::do_marking_st() {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
HandleMark hm;
|
HandleMark hm;
|
||||||
|
|
||||||
// Temporarily make refs discovery single threaded (non-MT)
|
// Temporarily make refs discovery single threaded (non-MT)
|
||||||
ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false);
|
ReferenceProcessorMTDiscoveryMutator rp_mut_discovery(ref_processor(), false);
|
||||||
MarkFromRootsClosure markFromRootsClosure(this, _span, &_markBitMap,
|
MarkFromRootsClosure markFromRootsClosure(this, _span, &_markBitMap,
|
||||||
&_markStack, CMSYield && asynch);
|
&_markStack, CMSYield);
|
||||||
// the last argument to iterate indicates whether the iteration
|
// the last argument to iterate indicates whether the iteration
|
||||||
// should be incremental with periodic yields.
|
// should be incremental with periodic yields.
|
||||||
_markBitMap.iterate(&markFromRootsClosure);
|
_markBitMap.iterate(&markFromRootsClosure);
|
||||||
|
@ -4169,7 +3882,7 @@ bool CMSCollector::do_marking_st(bool asynch) {
|
||||||
// occurred; we need to do a fresh iteration from the
|
// occurred; we need to do a fresh iteration from the
|
||||||
// indicated restart address.
|
// indicated restart address.
|
||||||
while (_restart_addr != NULL) {
|
while (_restart_addr != NULL) {
|
||||||
if (_foregroundGCIsActive && asynch) {
|
if (_foregroundGCIsActive) {
|
||||||
// We may be running into repeated stack overflows, having
|
// We may be running into repeated stack overflows, having
|
||||||
// reached the limit of the stack size, while making very
|
// reached the limit of the stack size, while making very
|
||||||
// slow forward progress. It may be best to bail out and
|
// slow forward progress. It may be best to bail out and
|
||||||
|
@ -4703,8 +4416,7 @@ void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freel
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::checkpointRootsFinal(bool asynch,
|
void CMSCollector::checkpointRootsFinal() {
|
||||||
bool clear_all_soft_refs, bool init_mark_was_synchronous) {
|
|
||||||
assert(_collectorState == FinalMarking, "incorrect state transition?");
|
assert(_collectorState == FinalMarking, "incorrect state transition?");
|
||||||
check_correct_thread_executing();
|
check_correct_thread_executing();
|
||||||
// world is stopped at this checkpoint
|
// world is stopped at this checkpoint
|
||||||
|
@ -4721,7 +4433,7 @@ void CMSCollector::checkpointRootsFinal(bool asynch,
|
||||||
_young_gen->used() / K,
|
_young_gen->used() / K,
|
||||||
_young_gen->capacity() / K);
|
_young_gen->capacity() / K);
|
||||||
}
|
}
|
||||||
if (asynch) {
|
{
|
||||||
if (CMSScavengeBeforeRemark) {
|
if (CMSScavengeBeforeRemark) {
|
||||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||||
// Temporarily set flag to false, GCH->do_collection will
|
// Temporarily set flag to false, GCH->do_collection will
|
||||||
|
@ -4742,21 +4454,14 @@ void CMSCollector::checkpointRootsFinal(bool asynch,
|
||||||
FreelistLocker x(this);
|
FreelistLocker x(this);
|
||||||
MutexLockerEx y(bitMapLock(),
|
MutexLockerEx y(bitMapLock(),
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
assert(!init_mark_was_synchronous, "but that's impossible!");
|
checkpointRootsFinalWork();
|
||||||
checkpointRootsFinalWork(asynch, clear_all_soft_refs, false);
|
|
||||||
} else {
|
|
||||||
// already have all the locks
|
|
||||||
checkpointRootsFinalWork(asynch, clear_all_soft_refs,
|
|
||||||
init_mark_was_synchronous);
|
|
||||||
}
|
}
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
SpecializationStats::print();
|
SpecializationStats::print();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::checkpointRootsFinalWork(bool asynch,
|
void CMSCollector::checkpointRootsFinalWork() {
|
||||||
bool clear_all_soft_refs, bool init_mark_was_synchronous) {
|
|
||||||
|
|
||||||
NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());)
|
NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());)
|
||||||
|
|
||||||
assert(haveFreelistLocks(), "must have free list locks");
|
assert(haveFreelistLocks(), "must have free list locks");
|
||||||
|
@ -4773,60 +4478,54 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
|
||||||
assert(haveFreelistLocks(), "must have free list locks");
|
assert(haveFreelistLocks(), "must have free list locks");
|
||||||
assert_lock_strong(bitMapLock());
|
assert_lock_strong(bitMapLock());
|
||||||
|
|
||||||
if (!init_mark_was_synchronous) {
|
// We might assume that we need not fill TLAB's when
|
||||||
// We might assume that we need not fill TLAB's when
|
// CMSScavengeBeforeRemark is set, because we may have just done
|
||||||
// CMSScavengeBeforeRemark is set, because we may have just done
|
// a scavenge which would have filled all TLAB's -- and besides
|
||||||
// a scavenge which would have filled all TLAB's -- and besides
|
// Eden would be empty. This however may not always be the case --
|
||||||
// Eden would be empty. This however may not always be the case --
|
// for instance although we asked for a scavenge, it may not have
|
||||||
// for instance although we asked for a scavenge, it may not have
|
// happened because of a JNI critical section. We probably need
|
||||||
// happened because of a JNI critical section. We probably need
|
// a policy for deciding whether we can in that case wait until
|
||||||
// a policy for deciding whether we can in that case wait until
|
// the critical section releases and then do the remark following
|
||||||
// the critical section releases and then do the remark following
|
// the scavenge, and skip it here. In the absence of that policy,
|
||||||
// the scavenge, and skip it here. In the absence of that policy,
|
// or of an indication of whether the scavenge did indeed occur,
|
||||||
// or of an indication of whether the scavenge did indeed occur,
|
// we cannot rely on TLAB's having been filled and must do
|
||||||
// we cannot rely on TLAB's having been filled and must do
|
// so here just in case a scavenge did not happen.
|
||||||
// so here just in case a scavenge did not happen.
|
gch->ensure_parsability(false); // fill TLAB's, but no need to retire them
|
||||||
gch->ensure_parsability(false); // fill TLAB's, but no need to retire them
|
// Update the saved marks which may affect the root scans.
|
||||||
// Update the saved marks which may affect the root scans.
|
gch->save_marks();
|
||||||
gch->save_marks();
|
|
||||||
|
|
||||||
if (CMSPrintEdenSurvivorChunks) {
|
if (CMSPrintEdenSurvivorChunks) {
|
||||||
print_eden_and_survivor_chunk_arrays();
|
print_eden_and_survivor_chunk_arrays();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
|
||||||
|
|
||||||
|
// Note on the role of the mod union table:
|
||||||
|
// Since the marker in "markFromRoots" marks concurrently with
|
||||||
|
// mutators, it is possible for some reachable objects not to have been
|
||||||
|
// scanned. For instance, an only reference to an object A was
|
||||||
|
// placed in object B after the marker scanned B. Unless B is rescanned,
|
||||||
|
// A would be collected. Such updates to references in marked objects
|
||||||
|
// are detected via the mod union table which is the set of all cards
|
||||||
|
// dirtied since the first checkpoint in this GC cycle and prior to
|
||||||
|
// the most recent young generation GC, minus those cleaned up by the
|
||||||
|
// concurrent precleaning.
|
||||||
|
if (CMSParallelRemarkEnabled && CollectedHeap::use_parallel_gc_threads()) {
|
||||||
|
GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());
|
||||||
|
do_remark_parallel();
|
||||||
|
} else {
|
||||||
|
GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false,
|
||||||
|
_gc_timer_cm, _gc_tracer_cm->gc_id());
|
||||||
|
do_remark_non_parallel();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
|
|
||||||
|
|
||||||
// Note on the role of the mod union table:
|
|
||||||
// Since the marker in "markFromRoots" marks concurrently with
|
|
||||||
// mutators, it is possible for some reachable objects not to have been
|
|
||||||
// scanned. For instance, an only reference to an object A was
|
|
||||||
// placed in object B after the marker scanned B. Unless B is rescanned,
|
|
||||||
// A would be collected. Such updates to references in marked objects
|
|
||||||
// are detected via the mod union table which is the set of all cards
|
|
||||||
// dirtied since the first checkpoint in this GC cycle and prior to
|
|
||||||
// the most recent young generation GC, minus those cleaned up by the
|
|
||||||
// concurrent precleaning.
|
|
||||||
if (CMSParallelRemarkEnabled && CollectedHeap::use_parallel_gc_threads()) {
|
|
||||||
GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());
|
|
||||||
do_remark_parallel();
|
|
||||||
} else {
|
|
||||||
GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false,
|
|
||||||
_gc_timer_cm, _gc_tracer_cm->gc_id());
|
|
||||||
do_remark_non_parallel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(!asynch, "Can't have init_mark_was_synchronous in asynch mode");
|
|
||||||
// The initial mark was stop-world, so there's no rescanning to
|
|
||||||
// do; go straight on to the next step below.
|
|
||||||
}
|
}
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
|
|
||||||
{
|
{
|
||||||
NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());)
|
NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());)
|
||||||
refProcessingWork(asynch, clear_all_soft_refs);
|
refProcessingWork();
|
||||||
}
|
}
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
|
@ -5872,8 +5571,7 @@ void CMSRefProcTaskExecutor::execute(EnqueueTask& task)
|
||||||
workers->run_task(&enq_task);
|
workers->run_task(&enq_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
|
void CMSCollector::refProcessingWork() {
|
||||||
|
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
HandleMark hm;
|
HandleMark hm;
|
||||||
|
|
||||||
|
@ -5881,7 +5579,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
|
||||||
assert(rp->span().equals(_span), "Spans should be equal");
|
assert(rp->span().equals(_span), "Spans should be equal");
|
||||||
assert(!rp->enqueuing_is_done(), "Enqueuing should not be complete");
|
assert(!rp->enqueuing_is_done(), "Enqueuing should not be complete");
|
||||||
// Process weak references.
|
// Process weak references.
|
||||||
rp->setup_policy(clear_all_soft_refs);
|
rp->setup_policy(false);
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
|
|
||||||
CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap,
|
CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap,
|
||||||
|
@ -6005,7 +5703,7 @@ void CMSCollector::check_correct_thread_executing() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void CMSCollector::sweep(bool asynch) {
|
void CMSCollector::sweep() {
|
||||||
assert(_collectorState == Sweeping, "just checking");
|
assert(_collectorState == Sweeping, "just checking");
|
||||||
check_correct_thread_executing();
|
check_correct_thread_executing();
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
|
@ -6019,14 +5717,14 @@ void CMSCollector::sweep(bool asynch) {
|
||||||
assert(!_intra_sweep_timer.is_active(), "Should not be active");
|
assert(!_intra_sweep_timer.is_active(), "Should not be active");
|
||||||
_intra_sweep_timer.reset();
|
_intra_sweep_timer.reset();
|
||||||
_intra_sweep_timer.start();
|
_intra_sweep_timer.start();
|
||||||
if (asynch) {
|
{
|
||||||
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
|
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
|
||||||
CMSPhaseAccounting pa(this, "sweep", _gc_tracer_cm->gc_id(), !PrintGCDetails);
|
CMSPhaseAccounting pa(this, "sweep", _gc_tracer_cm->gc_id(), !PrintGCDetails);
|
||||||
// First sweep the old gen
|
// First sweep the old gen
|
||||||
{
|
{
|
||||||
CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(),
|
CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(),
|
||||||
bitMapLock());
|
bitMapLock());
|
||||||
sweepWork(_cmsGen, asynch);
|
sweepWork(_cmsGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Universe::_heap_*_at_gc figures.
|
// Update Universe::_heap_*_at_gc figures.
|
||||||
|
@ -6040,13 +5738,6 @@ void CMSCollector::sweep(bool asynch) {
|
||||||
Universe::update_heap_info_at_gc();
|
Universe::update_heap_info_at_gc();
|
||||||
_collectorState = Resizing;
|
_collectorState = Resizing;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// already have needed locks
|
|
||||||
sweepWork(_cmsGen, asynch);
|
|
||||||
// Update heap occupancy information which is used as
|
|
||||||
// input to soft ref clearing policy at the next gc.
|
|
||||||
Universe::update_heap_info_at_gc();
|
|
||||||
_collectorState = Resizing;
|
|
||||||
}
|
}
|
||||||
verify_work_stacks_empty();
|
verify_work_stacks_empty();
|
||||||
verify_overflow_empty();
|
verify_overflow_empty();
|
||||||
|
@ -6141,18 +5832,16 @@ void ConcurrentMarkSweepGeneration::update_gc_stats(int current_level,
|
||||||
|
|
||||||
void ConcurrentMarkSweepGeneration::rotate_debug_collection_type() {
|
void ConcurrentMarkSweepGeneration::rotate_debug_collection_type() {
|
||||||
if (PrintGCDetails && Verbose) {
|
if (PrintGCDetails && Verbose) {
|
||||||
gclog_or_tty->print("Rotate from %d ", _debug_collection_type);
|
if (_debug_concurrent_cycle) {
|
||||||
}
|
gclog_or_tty->print_cr("Rotate from concurrent to STW collections");
|
||||||
_debug_collection_type = (CollectionTypes) (_debug_collection_type + 1);
|
} else {
|
||||||
_debug_collection_type =
|
gclog_or_tty->print_cr("Rotate from STW to concurrent collections");
|
||||||
(CollectionTypes) (_debug_collection_type % Unknown_collection_type);
|
}
|
||||||
if (PrintGCDetails && Verbose) {
|
|
||||||
gclog_or_tty->print_cr("to %d ", _debug_collection_type);
|
|
||||||
}
|
}
|
||||||
|
_debug_concurrent_cycle = !_debug_concurrent_cycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen) {
|
||||||
bool asynch) {
|
|
||||||
// We iterate over the space(s) underlying this generation,
|
// We iterate over the space(s) underlying this generation,
|
||||||
// checking the mark bit map to see if the bits corresponding
|
// checking the mark bit map to see if the bits corresponding
|
||||||
// to specific blocks are marked or not. Blocks that are
|
// to specific blocks are marked or not. Blocks that are
|
||||||
|
@ -6180,9 +5869,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
||||||
|
|
||||||
// check that we hold the requisite locks
|
// check that we hold the requisite locks
|
||||||
assert(have_cms_token(), "Should hold cms token");
|
assert(have_cms_token(), "Should hold cms token");
|
||||||
assert( (asynch && ConcurrentMarkSweepThread::cms_thread_has_cms_token())
|
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), "Should possess CMS token to sweep");
|
||||||
|| (!asynch && ConcurrentMarkSweepThread::vm_thread_has_cms_token()),
|
|
||||||
"Should possess CMS token to sweep");
|
|
||||||
assert_lock_strong(gen->freelistLock());
|
assert_lock_strong(gen->freelistLock());
|
||||||
assert_lock_strong(bitMapLock());
|
assert_lock_strong(bitMapLock());
|
||||||
|
|
||||||
|
@ -6194,8 +5881,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
||||||
gen->setNearLargestChunk();
|
gen->setNearLargestChunk();
|
||||||
|
|
||||||
{
|
{
|
||||||
SweepClosure sweepClosure(this, gen, &_markBitMap,
|
SweepClosure sweepClosure(this, gen, &_markBitMap, CMSYield);
|
||||||
CMSYield && asynch);
|
|
||||||
gen->cmsSpace()->blk_iterate_careful(&sweepClosure);
|
gen->cmsSpace()->blk_iterate_careful(&sweepClosure);
|
||||||
// We need to free-up/coalesce garbage/blocks from a
|
// We need to free-up/coalesce garbage/blocks from a
|
||||||
// co-terminal free run. This is done in the SweepClosure
|
// co-terminal free run. This is done in the SweepClosure
|
||||||
|
@ -6213,8 +5899,8 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
||||||
|
|
||||||
// Reset CMS data structures (for now just the marking bit map)
|
// Reset CMS data structures (for now just the marking bit map)
|
||||||
// preparatory for the next cycle.
|
// preparatory for the next cycle.
|
||||||
void CMSCollector::reset(bool asynch) {
|
void CMSCollector::reset(bool concurrent) {
|
||||||
if (asynch) {
|
if (concurrent) {
|
||||||
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
||||||
|
|
||||||
// If the state is not "Resetting", the foreground thread
|
// If the state is not "Resetting", the foreground thread
|
||||||
|
@ -6293,7 +5979,7 @@ void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case CMS_op_checkpointRootsInitial: {
|
case CMS_op_checkpointRootsInitial: {
|
||||||
SvcGCMarker sgcm(SvcGCMarker::OTHER);
|
SvcGCMarker sgcm(SvcGCMarker::OTHER);
|
||||||
checkpointRootsInitial(true); // asynch
|
checkpointRootsInitial();
|
||||||
if (PrintGC) {
|
if (PrintGC) {
|
||||||
_cmsGen->printOccupancy("initial-mark");
|
_cmsGen->printOccupancy("initial-mark");
|
||||||
}
|
}
|
||||||
|
@ -6301,9 +5987,7 @@ void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) {
|
||||||
}
|
}
|
||||||
case CMS_op_checkpointRootsFinal: {
|
case CMS_op_checkpointRootsFinal: {
|
||||||
SvcGCMarker sgcm(SvcGCMarker::OTHER);
|
SvcGCMarker sgcm(SvcGCMarker::OTHER);
|
||||||
checkpointRootsFinal(true, // asynch
|
checkpointRootsFinal();
|
||||||
false, // !clear_all_soft_refs
|
|
||||||
false); // !init_mark_was_synchronous
|
|
||||||
if (PrintGC) {
|
if (PrintGC) {
|
||||||
_cmsGen->printOccupancy("remark");
|
_cmsGen->printOccupancy("remark");
|
||||||
}
|
}
|
||||||
|
@ -7193,8 +6877,7 @@ Par_MarkFromRootsClosure::Par_MarkFromRootsClosure(CMSConcMarkingTask* task,
|
||||||
CMSCollector* collector, MemRegion span,
|
CMSCollector* collector, MemRegion span,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
OopTaskQueue* work_queue,
|
OopTaskQueue* work_queue,
|
||||||
CMSMarkStack* overflow_stack,
|
CMSMarkStack* overflow_stack):
|
||||||
bool should_yield):
|
|
||||||
_collector(collector),
|
_collector(collector),
|
||||||
_whole_span(collector->_span),
|
_whole_span(collector->_span),
|
||||||
_span(span),
|
_span(span),
|
||||||
|
@ -7202,7 +6885,6 @@ Par_MarkFromRootsClosure::Par_MarkFromRootsClosure(CMSConcMarkingTask* task,
|
||||||
_mut(&collector->_modUnionTable),
|
_mut(&collector->_modUnionTable),
|
||||||
_work_queue(work_queue),
|
_work_queue(work_queue),
|
||||||
_overflow_stack(overflow_stack),
|
_overflow_stack(overflow_stack),
|
||||||
_yield(should_yield),
|
|
||||||
_skip_bits(0),
|
_skip_bits(0),
|
||||||
_task(task)
|
_task(task)
|
||||||
{
|
{
|
||||||
|
|
|
@ -608,7 +608,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
GCHeapSummary _last_heap_summary;
|
GCHeapSummary _last_heap_summary;
|
||||||
MetaspaceSummary _last_metaspace_summary;
|
MetaspaceSummary _last_metaspace_summary;
|
||||||
|
|
||||||
void register_foreground_gc_start(GCCause::Cause cause);
|
|
||||||
void register_gc_start(GCCause::Cause cause);
|
void register_gc_start(GCCause::Cause cause);
|
||||||
void register_gc_end();
|
void register_gc_end();
|
||||||
void save_heap_summary();
|
void save_heap_summary();
|
||||||
|
@ -695,8 +694,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
int _numYields;
|
int _numYields;
|
||||||
size_t _numDirtyCards;
|
size_t _numDirtyCards;
|
||||||
size_t _sweep_count;
|
size_t _sweep_count;
|
||||||
// Number of full gc's since the last concurrent gc.
|
|
||||||
uint _full_gcs_since_conc_gc;
|
|
||||||
|
|
||||||
// Occupancy used for bootstrapping stats
|
// Occupancy used for bootstrapping stats
|
||||||
double _bootstrap_occupancy;
|
double _bootstrap_occupancy;
|
||||||
|
@ -760,14 +757,14 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
NOT_PRODUCT(bool par_simulate_overflow();) // MT version
|
NOT_PRODUCT(bool par_simulate_overflow();) // MT version
|
||||||
|
|
||||||
// CMS work methods
|
// CMS work methods
|
||||||
void checkpointRootsInitialWork(bool asynch); // Initial checkpoint work
|
void checkpointRootsInitialWork(); // Initial checkpoint work
|
||||||
|
|
||||||
// A return value of false indicates failure due to stack overflow
|
// A return value of false indicates failure due to stack overflow
|
||||||
bool markFromRootsWork(bool asynch); // Concurrent marking work
|
bool markFromRootsWork(); // Concurrent marking work
|
||||||
|
|
||||||
public: // FIX ME!!! only for testing
|
public: // FIX ME!!! only for testing
|
||||||
bool do_marking_st(bool asynch); // Single-threaded marking
|
bool do_marking_st(); // Single-threaded marking
|
||||||
bool do_marking_mt(bool asynch); // Multi-threaded marking
|
bool do_marking_mt(); // Multi-threaded marking
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -788,20 +785,19 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
void reset_survivor_plab_arrays();
|
void reset_survivor_plab_arrays();
|
||||||
|
|
||||||
// Final (second) checkpoint work
|
// Final (second) checkpoint work
|
||||||
void checkpointRootsFinalWork(bool asynch, bool clear_all_soft_refs,
|
void checkpointRootsFinalWork();
|
||||||
bool init_mark_was_synchronous);
|
|
||||||
// Work routine for parallel version of remark
|
// Work routine for parallel version of remark
|
||||||
void do_remark_parallel();
|
void do_remark_parallel();
|
||||||
// Work routine for non-parallel version of remark
|
// Work routine for non-parallel version of remark
|
||||||
void do_remark_non_parallel();
|
void do_remark_non_parallel();
|
||||||
// Reference processing work routine (during second checkpoint)
|
// Reference processing work routine (during second checkpoint)
|
||||||
void refProcessingWork(bool asynch, bool clear_all_soft_refs);
|
void refProcessingWork();
|
||||||
|
|
||||||
// Concurrent sweeping work
|
// Concurrent sweeping work
|
||||||
void sweepWork(ConcurrentMarkSweepGeneration* gen, bool asynch);
|
void sweepWork(ConcurrentMarkSweepGeneration* gen);
|
||||||
|
|
||||||
// (Concurrent) resetting of support data structures
|
// (Concurrent) resetting of support data structures
|
||||||
void reset(bool asynch);
|
void reset(bool concurrent);
|
||||||
|
|
||||||
// Clear _expansion_cause fields of constituent generations
|
// Clear _expansion_cause fields of constituent generations
|
||||||
void clear_expansion_cause();
|
void clear_expansion_cause();
|
||||||
|
@ -810,22 +806,10 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
// used regions of each generation to limit the extent of sweep
|
// used regions of each generation to limit the extent of sweep
|
||||||
void save_sweep_limits();
|
void save_sweep_limits();
|
||||||
|
|
||||||
// A work method used by foreground collection to determine
|
|
||||||
// what type of collection (compacting or not, continuing or fresh)
|
|
||||||
// it should do.
|
|
||||||
void decide_foreground_collection_type(bool clear_all_soft_refs,
|
|
||||||
bool* should_compact, bool* should_start_over);
|
|
||||||
|
|
||||||
// A work method used by the foreground collector to do
|
// A work method used by the foreground collector to do
|
||||||
// a mark-sweep-compact.
|
// a mark-sweep-compact.
|
||||||
void do_compaction_work(bool clear_all_soft_refs);
|
void do_compaction_work(bool clear_all_soft_refs);
|
||||||
|
|
||||||
// A work method used by the foreground collector to do
|
|
||||||
// a mark-sweep, after taking over from a possibly on-going
|
|
||||||
// concurrent mark-sweep collection.
|
|
||||||
void do_mark_sweep_work(bool clear_all_soft_refs,
|
|
||||||
CollectorState first_state, bool should_start_over);
|
|
||||||
|
|
||||||
// Work methods for reporting concurrent mode interruption or failure
|
// Work methods for reporting concurrent mode interruption or failure
|
||||||
bool is_external_interruption();
|
bool is_external_interruption();
|
||||||
void report_concurrent_mode_interruption();
|
void report_concurrent_mode_interruption();
|
||||||
|
@ -868,15 +852,13 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
// Locking checks
|
// Locking checks
|
||||||
NOT_PRODUCT(static bool have_cms_token();)
|
NOT_PRODUCT(static bool have_cms_token();)
|
||||||
|
|
||||||
// XXXPERM bool should_collect(bool full, size_t size, bool tlab);
|
|
||||||
bool shouldConcurrentCollect();
|
bool shouldConcurrentCollect();
|
||||||
|
|
||||||
void collect(bool full,
|
void collect(bool full,
|
||||||
bool clear_all_soft_refs,
|
bool clear_all_soft_refs,
|
||||||
size_t size,
|
size_t size,
|
||||||
bool tlab);
|
bool tlab);
|
||||||
void collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause);
|
void collect_in_background(GCCause::Cause cause);
|
||||||
void collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause);
|
|
||||||
|
|
||||||
// In support of ExplicitGCInvokesConcurrent
|
// In support of ExplicitGCInvokesConcurrent
|
||||||
static void request_full_gc(unsigned int full_gc_count, GCCause::Cause cause);
|
static void request_full_gc(unsigned int full_gc_count, GCCause::Cause cause);
|
||||||
|
@ -928,18 +910,16 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||||
void directAllocated(HeapWord* start, size_t size);
|
void directAllocated(HeapWord* start, size_t size);
|
||||||
|
|
||||||
// Main CMS steps and related support
|
// Main CMS steps and related support
|
||||||
void checkpointRootsInitial(bool asynch);
|
void checkpointRootsInitial();
|
||||||
bool markFromRoots(bool asynch); // a return value of false indicates failure
|
bool markFromRoots(); // a return value of false indicates failure
|
||||||
// due to stack overflow
|
// due to stack overflow
|
||||||
void preclean();
|
void preclean();
|
||||||
void checkpointRootsFinal(bool asynch, bool clear_all_soft_refs,
|
void checkpointRootsFinal();
|
||||||
bool init_mark_was_synchronous);
|
void sweep();
|
||||||
void sweep(bool asynch);
|
|
||||||
|
|
||||||
// Check that the currently executing thread is the expected
|
// Check that the currently executing thread is the expected
|
||||||
// one (foreground collector or background collector).
|
// one (foreground collector or background collector).
|
||||||
static void check_correct_thread_executing() PRODUCT_RETURN;
|
static void check_correct_thread_executing() PRODUCT_RETURN;
|
||||||
// XXXPERM void print_statistics() PRODUCT_RETURN;
|
|
||||||
|
|
||||||
bool is_cms_reachable(HeapWord* addr);
|
bool is_cms_reachable(HeapWord* addr);
|
||||||
|
|
||||||
|
@ -1060,14 +1040,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||||
// In support of MinChunkSize being larger than min object size
|
// In support of MinChunkSize being larger than min object size
|
||||||
const double _dilatation_factor;
|
const double _dilatation_factor;
|
||||||
|
|
||||||
enum CollectionTypes {
|
bool _debug_concurrent_cycle;
|
||||||
Concurrent_collection_type = 0,
|
|
||||||
MS_foreground_collection_type = 1,
|
|
||||||
MSC_foreground_collection_type = 2,
|
|
||||||
Unknown_collection_type = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
CollectionTypes _debug_collection_type;
|
|
||||||
|
|
||||||
// True if a compacting collection was done.
|
// True if a compacting collection was done.
|
||||||
bool _did_compact;
|
bool _did_compact;
|
||||||
|
@ -1152,7 +1125,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||||
// hack to allow the collection of the younger gen first if the flag is
|
// hack to allow the collection of the younger gen first if the flag is
|
||||||
// set.
|
// set.
|
||||||
virtual bool full_collects_younger_generations() const {
|
virtual bool full_collects_younger_generations() const {
|
||||||
return UseCMSCompactAtFullCollection && !ScavengeBeforeFullGC;
|
return !ScavengeBeforeFullGC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void space_iterate(SpaceClosure* blk, bool usedOnly = false);
|
void space_iterate(SpaceClosure* blk, bool usedOnly = false);
|
||||||
|
@ -1296,7 +1269,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||||
// collection.
|
// collection.
|
||||||
void compute_new_size_free_list();
|
void compute_new_size_free_list();
|
||||||
|
|
||||||
CollectionTypes debug_collection_type() { return _debug_collection_type; }
|
bool debug_concurrent_cycle() { return _debug_concurrent_cycle; }
|
||||||
void rotate_debug_collection_type();
|
void rotate_debug_collection_type();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1344,7 +1317,6 @@ class Par_MarkFromRootsClosure: public BitMapClosure {
|
||||||
CMSBitMap* _mut;
|
CMSBitMap* _mut;
|
||||||
OopTaskQueue* _work_queue;
|
OopTaskQueue* _work_queue;
|
||||||
CMSMarkStack* _overflow_stack;
|
CMSMarkStack* _overflow_stack;
|
||||||
bool _yield;
|
|
||||||
int _skip_bits;
|
int _skip_bits;
|
||||||
HeapWord* _finger;
|
HeapWord* _finger;
|
||||||
HeapWord* _threshold;
|
HeapWord* _threshold;
|
||||||
|
@ -1354,8 +1326,7 @@ class Par_MarkFromRootsClosure: public BitMapClosure {
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
OopTaskQueue* work_queue,
|
OopTaskQueue* work_queue,
|
||||||
CMSMarkStack* overflow_stack,
|
CMSMarkStack* overflow_stack);
|
||||||
bool should_yield);
|
|
||||||
bool do_bit(size_t offset);
|
bool do_bit(size_t offset);
|
||||||
inline void do_yield_check();
|
inline void do_yield_check();
|
||||||
|
|
||||||
|
|
|
@ -398,8 +398,7 @@ inline void MarkFromRootsClosure::do_yield_check() {
|
||||||
|
|
||||||
inline void Par_MarkFromRootsClosure::do_yield_check() {
|
inline void Par_MarkFromRootsClosure::do_yield_check() {
|
||||||
if (ConcurrentMarkSweepThread::should_yield() &&
|
if (ConcurrentMarkSweepThread::should_yield() &&
|
||||||
!_collector->foregroundGCIsActive() &&
|
!_collector->foregroundGCIsActive()) {
|
||||||
_yield) {
|
|
||||||
do_yield_work();
|
do_yield_work();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ void ConcurrentMarkSweepThread::run() {
|
||||||
if (_should_terminate) break;
|
if (_should_terminate) break;
|
||||||
GCCause::Cause cause = _collector->_full_gc_requested ?
|
GCCause::Cause cause = _collector->_full_gc_requested ?
|
||||||
_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
|
_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
|
||||||
_collector->collect_in_background(false, cause);
|
_collector->collect_in_background(cause);
|
||||||
}
|
}
|
||||||
assert(_should_terminate, "just checking");
|
assert(_should_terminate, "just checking");
|
||||||
// Check that the state of any protocol for synchronization
|
// Check that the state of any protocol for synchronization
|
||||||
|
|
|
@ -2202,15 +2202,6 @@ void Arguments::check_deprecated_gc_flags() {
|
||||||
warning("DefaultMaxRAMFraction is deprecated and will likely be removed in a future release. "
|
warning("DefaultMaxRAMFraction is deprecated and will likely be removed in a future release. "
|
||||||
"Use MaxRAMFraction instead.");
|
"Use MaxRAMFraction instead.");
|
||||||
}
|
}
|
||||||
if (FLAG_IS_CMDLINE(UseCMSCompactAtFullCollection)) {
|
|
||||||
warning("UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release.");
|
|
||||||
}
|
|
||||||
if (FLAG_IS_CMDLINE(CMSFullGCsBeforeCompaction)) {
|
|
||||||
warning("CMSFullGCsBeforeCompaction is deprecated and will likely be removed in a future release.");
|
|
||||||
}
|
|
||||||
if (FLAG_IS_CMDLINE(UseCMSCollectionPassing)) {
|
|
||||||
warning("UseCMSCollectionPassing is deprecated and will likely be removed in a future release.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check stack pages settings
|
// Check stack pages settings
|
||||||
|
|
|
@ -1529,9 +1529,6 @@ class CommandLineFlags {
|
||||||
product(bool, UseCMSBestFit, true, \
|
product(bool, UseCMSBestFit, true, \
|
||||||
"Use CMS best fit allocation strategy") \
|
"Use CMS best fit allocation strategy") \
|
||||||
\
|
\
|
||||||
product(bool, UseCMSCollectionPassing, true, \
|
|
||||||
"Use passing of collection from background to foreground") \
|
|
||||||
\
|
|
||||||
product(bool, UseParNewGC, false, \
|
product(bool, UseParNewGC, false, \
|
||||||
"Use parallel threads in the new generation") \
|
"Use parallel threads in the new generation") \
|
||||||
\
|
\
|
||||||
|
@ -1707,16 +1704,6 @@ class CommandLineFlags {
|
||||||
"When CMS class unloading is enabled, the maximum CMS cycle " \
|
"When CMS class unloading is enabled, the maximum CMS cycle " \
|
||||||
"count for which classes may not be unloaded") \
|
"count for which classes may not be unloaded") \
|
||||||
\
|
\
|
||||||
product(bool, CMSCompactWhenClearAllSoftRefs, true, \
|
|
||||||
"Compact when asked to collect CMS gen with " \
|
|
||||||
"clear_all_soft_refs()") \
|
|
||||||
\
|
|
||||||
product(bool, UseCMSCompactAtFullCollection, true, \
|
|
||||||
"Use Mark-Sweep-Compact algorithm at full collections") \
|
|
||||||
\
|
|
||||||
product(uintx, CMSFullGCsBeforeCompaction, 0, \
|
|
||||||
"Number of CMS full collection done before compaction if > 0") \
|
|
||||||
\
|
|
||||||
develop(intx, CMSDictionaryChoice, 0, \
|
develop(intx, CMSDictionaryChoice, 0, \
|
||||||
"Use BinaryTreeDictionary as default in the CMS generation") \
|
"Use BinaryTreeDictionary as default in the CMS generation") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test CheckAllocateAndSystemGC
|
|
||||||
* @summary CMS: assert(used() == used_after_gc && used_after_gc <= capacity()) failed: used: 0 used_after_gc: 292080 capacity: 1431699456
|
|
||||||
* @bug 8013032
|
|
||||||
* @key gc
|
|
||||||
* @key regression
|
|
||||||
* @library /testlibrary
|
|
||||||
* @run main/othervm CheckAllocateAndSystemGC
|
|
||||||
* @author jon.masamitsu@oracle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.oracle.java.testlibrary.*;
|
|
||||||
|
|
||||||
public class CheckAllocateAndSystemGC {
|
|
||||||
public static void main(String args[]) throws Exception {
|
|
||||||
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
|
||||||
"-showversion",
|
|
||||||
"-XX:+UseConcMarkSweepGC",
|
|
||||||
"-Xmn4m",
|
|
||||||
"-XX:MaxTenuringThreshold=1",
|
|
||||||
"-XX:-UseCMSCompactAtFullCollection",
|
|
||||||
"CheckAllocateAndSystemGC$AllocateAndSystemGC"
|
|
||||||
);
|
|
||||||
|
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
|
||||||
|
|
||||||
output.shouldNotContain("error");
|
|
||||||
|
|
||||||
output.shouldHaveExitValue(0);
|
|
||||||
}
|
|
||||||
static class AllocateAndSystemGC {
|
|
||||||
public static void main(String [] args) {
|
|
||||||
Integer x[] = new Integer [1000];
|
|
||||||
// Allocate enough objects to cause a minor collection.
|
|
||||||
// These allocations suffice for a 4m young geneneration.
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
Integer y[] = new Integer[10000];
|
|
||||||
}
|
|
||||||
System.gc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test SystemGCOnForegroundCollector
|
|
||||||
* @summary CMS: Call reset_after_compaction() only if a compaction has been done
|
|
||||||
* @bug 8013184
|
|
||||||
* @key gc
|
|
||||||
* @key regression
|
|
||||||
* @library /testlibrary
|
|
||||||
* @run main/othervm SystemGCOnForegroundCollector
|
|
||||||
* @author jon.masamitsu@oracle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.oracle.java.testlibrary.*;
|
|
||||||
|
|
||||||
public class SystemGCOnForegroundCollector {
|
|
||||||
public static void main(String args[]) throws Exception {
|
|
||||||
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
|
||||||
"-showversion",
|
|
||||||
"-XX:+UseConcMarkSweepGC",
|
|
||||||
"-XX:MaxTenuringThreshold=1",
|
|
||||||
"-XX:-UseCMSCompactAtFullCollection",
|
|
||||||
ThreePlusMSSystemGC.class.getName()
|
|
||||||
);
|
|
||||||
|
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
|
||||||
|
|
||||||
output.shouldNotContain("error");
|
|
||||||
|
|
||||||
output.shouldHaveExitValue(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ThreePlusMSSystemGC {
|
|
||||||
public static void main(String [] args) {
|
|
||||||
// From running this test 3 System.gc() were always
|
|
||||||
// enough to see the failure but the cause of the failure
|
|
||||||
// depends on how objects are allocated in the CMS generation
|
|
||||||
// which is non-deterministic. Use 30 iterations for a more
|
|
||||||
// reliable test.
|
|
||||||
for (int i = 0; i < 30; i++) {
|
|
||||||
System.gc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @test TestCMSForegroundFlags
|
|
||||||
* @key gc
|
|
||||||
* @bug 8027132
|
|
||||||
* @summary Test that the deprecated CMS foreground collector flags print warning messages
|
|
||||||
* @library /testlibrary
|
|
||||||
* @run main TestCMSForegroundFlags -XX:-UseCMSCompactAtFullCollection UseCMSCompactAtFullCollection
|
|
||||||
* @run main TestCMSForegroundFlags -XX:CMSFullGCsBeforeCompaction=4 CMSFullGCsBeforeCompaction
|
|
||||||
* @run main TestCMSForegroundFlags -XX:-UseCMSCollectionPassing UseCMSCollectionPassing
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
|
||||||
import com.oracle.java.testlibrary.ProcessTools;
|
|
||||||
|
|
||||||
public class TestCMSForegroundFlags {
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args.length != 2) {
|
|
||||||
throw new Exception("Expected two arguments,flagValue and flagName");
|
|
||||||
}
|
|
||||||
String flagValue = args[0];
|
|
||||||
String flagName = args[1];
|
|
||||||
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flagValue, "-version");
|
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
|
||||||
output.shouldContain("warning: " + flagName + " is deprecated and will likely be removed in a future release.");
|
|
||||||
output.shouldNotContain("error");
|
|
||||||
output.shouldHaveExitValue(0);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue