From f903d5a1a1c8c9795f2b541594ff22fd6bd574c1 Mon Sep 17 00:00:00 2001 From: ysr Date: Sun, 16 Mar 2008 21:57:25 -0700 Subject: [PATCH] 6634032: CMS: Need CMSInitiatingPermOccupancyFraction for perm, divorcing from CMSInitiatingOccupancyFraction Summary: The option CMSInitiatingPermOccupancyFraction now controls perm triggering threshold. Even though the actual value of the threshold has not yet been changed, so there is no change in policy, we now have the infrastructure in place for dynamically deciding when to collect the perm gen, an issue that will be addressed in the near future. Reviewed-by: jmasa --- .../concurrentMarkSweepGeneration.cpp | 239 +++++++++++------- .../concurrentMarkSweepGeneration.hpp | 45 ++-- .../concurrentMarkSweepGeneration.inline.hpp | 2 +- src/share/vm/runtime/globals.hpp | 21 +- 4 files changed, 198 insertions(+), 109 deletions(-) diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index eff7a042e..42593073c 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -225,6 +225,34 @@ ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration( assert(_dilatation_factor >= 1.0, "from previous assert"); } + +// The field "_initiating_occupancy" represents the occupancy percentage +// at which we trigger a new collection cycle. Unless explicitly specified +// via CMSInitiating[Perm]OccupancyFraction (argument "io" below), it +// is calculated by: +// +// Let "f" be MinHeapFreeRatio in +// +// _intiating_occupancy = 100-f + +// f * (CMSTrigger[Perm]Ratio/100) +// where CMSTrigger[Perm]Ratio is the argument "tr" below. +// +// That is, if we assume the heap is at its desired maximum occupancy at the +// end of a collection, we let CMSTrigger[Perm]Ratio of the (purported) free +// space be allocated before initiating a new collection cycle. +// +void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) { + assert(io <= 100 && tr >= 0 && tr <= 100, "Check the arguments"); + if (io >= 0) { + _initiating_occupancy = (double)io / 100.0; + } else { + _initiating_occupancy = ((100 - MinHeapFreeRatio) + + (double)(tr * MinHeapFreeRatio) / 100.0) + / 100.0; + } +} + + void ConcurrentMarkSweepGeneration::ref_processor_init() { assert(collector() != NULL, "no collector"); collector()->ref_processor_init(); @@ -520,8 +548,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, _verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"), _completed_initialization(false), _collector_policy(cp), - _unload_classes(false), - _unloaded_classes_last_cycle(false), + _should_unload_classes(false), + _concurrent_cycles_since_last_unload(0), _sweep_estimate(CMS_SweepWeight, CMS_SweepPadding) { if (ExplicitGCInvokesConcurrentAndUnloadsClasses) { @@ -642,26 +670,11 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen, } } - // "initiatingOccupancy" is the occupancy ratio at which we trigger - // a new collection cycle. Unless explicitly specified via - // CMSTriggerRatio, it is calculated by: - // Let "f" be MinHeapFreeRatio in - // - // intiatingOccupancy = 100-f + - // f * (CMSTriggerRatio/100) - // That is, if we assume the heap is at its desired maximum occupancy at the - // end of a collection, we let CMSTriggerRatio of the (purported) free - // space be allocated before initiating a new collection cycle. - if (CMSInitiatingOccupancyFraction > 0) { - _initiatingOccupancy = (double)CMSInitiatingOccupancyFraction / 100.0; - } else { - _initiatingOccupancy = ((100 - MinHeapFreeRatio) + - (double)(CMSTriggerRatio * - MinHeapFreeRatio) / 100.0) - / 100.0; - } + _cmsGen ->init_initiating_occupancy(CMSInitiatingOccupancyFraction, CMSTriggerRatio); + _permGen->init_initiating_occupancy(CMSInitiatingPermOccupancyFraction, CMSTriggerPermRatio); + // Clip CMSBootstrapOccupancy between 0 and 100. - _bootstrap_occupancy = ((double)MIN2((intx)100, MAX2((intx)0, CMSBootstrapOccupancy))) + _bootstrap_occupancy = ((double)MIN2((uintx)100, MAX2((uintx)0, CMSBootstrapOccupancy))) /(double)100; _full_gcs_since_conc_gc = 0; @@ -1413,7 +1426,8 @@ bool CMSCollector::shouldConcurrentCollect() { gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate()); gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); - gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", initiatingOccupancy()); + gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); + gclog_or_tty->print_cr("initiatingPermOccupancy=%3.7f", _permGen->initiating_occupancy()); } // ------------------------------------------------------------------ @@ -1446,22 +1460,36 @@ bool CMSCollector::shouldConcurrentCollect() { // old gen want a collection cycle started. Each may use // an appropriate criterion for making this decision. // XXX We need to make sure that the gen expansion - // criterion dovetails well with this. - if (_cmsGen->shouldConcurrentCollect(initiatingOccupancy())) { + // criterion dovetails well with this. XXX NEED TO FIX THIS + if (_cmsGen->should_concurrent_collect()) { if (Verbose && PrintGCDetails) { gclog_or_tty->print_cr("CMS old gen initiated"); } return true; } - if (cms_should_unload_classes() && - _permGen->shouldConcurrentCollect(initiatingOccupancy())) { - if (Verbose && PrintGCDetails) { - gclog_or_tty->print_cr("CMS perm gen initiated"); + // We start a collection if we believe an incremental collection may fail; + // this is not likely to be productive in practice because it's probably too + // late anyway. + GenCollectedHeap* gch = GenCollectedHeap::heap(); + assert(gch->collector_policy()->is_two_generation_policy(), + "You may want to check the correctness of the following"); + if (gch->incremental_collection_will_fail()) { + if (PrintGCDetails && Verbose) { + gclog_or_tty->print("CMSCollector: collect because incremental collection will fail "); } return true; } + if (CMSClassUnloadingEnabled && _permGen->should_concurrent_collect()) { + bool res = update_should_unload_classes(); + if (res) { + if (Verbose && PrintGCDetails) { + gclog_or_tty->print_cr("CMS perm gen initiated"); + } + return true; + } + } return false; } @@ -1471,32 +1499,36 @@ void CMSCollector::clear_expansion_cause() { _permGen->clear_expansion_cause(); } -bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect( - double initiatingOccupancy) { - // We should be conservative in starting a collection cycle. To - // start too eagerly runs the risk of collecting too often in the - // extreme. To collect too rarely falls back on full collections, - // which works, even if not optimum in terms of concurrent work. - // As a work around for too eagerly collecting, use the flag - // UseCMSInitiatingOccupancyOnly. This also has the advantage of - // giving the user an easily understandable way of controlling the - // collections. - // We want to start a new collection cycle if any of the following - // conditions hold: - // . our current occupancy exceeds the initiating occupancy, or - // . we recently needed to expand and have not since that expansion, - // collected, or - // . we are not using adaptive free lists and linear allocation is - // going to fail, or - // . (for old gen) incremental collection has already failed or - // may soon fail in the near future as we may not be able to absorb - // promotions. - assert_lock_strong(freelistLock()); +// We should be conservative in starting a collection cycle. To +// start too eagerly runs the risk of collecting too often in the +// extreme. To collect too rarely falls back on full collections, +// which works, even if not optimum in terms of concurrent work. +// As a work around for too eagerly collecting, use the flag +// UseCMSInitiatingOccupancyOnly. This also has the advantage of +// giving the user an easily understandable way of controlling the +// collections. +// We want to start a new collection cycle if any of the following +// conditions hold: +// . our current occupancy exceeds the configured initiating occupancy +// for this generation, or +// . we recently needed to expand this space and have not, since that +// expansion, done a collection of this generation, or +// . the underlying space believes that it may be a good idea to initiate +// a concurrent collection (this may be based on criteria such as the +// following: the space uses linear allocation and linear allocation is +// going to fail, or there is believed to be excessive fragmentation in +// the generation, etc... or ... +// [.(currently done by CMSCollector::shouldConcurrentCollect() only for +// the case of the old generation, not the perm generation; see CR 6543076): +// we may be approaching a point at which allocation requests may fail because +// we will be out of sufficient free space given allocation rate estimates.] +bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const { - if (occupancy() > initiatingOccupancy) { + assert_lock_strong(freelistLock()); + if (occupancy() > initiating_occupancy()) { if (PrintGCDetails && Verbose) { gclog_or_tty->print(" %s: collect because of occupancy %f / %f ", - short_name(), occupancy(), initiatingOccupancy); + short_name(), occupancy(), initiating_occupancy()); } return true; } @@ -1510,20 +1542,9 @@ bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect( } return true; } - GenCollectedHeap* gch = GenCollectedHeap::heap(); - assert(gch->collector_policy()->is_two_generation_policy(), - "You may want to check the correctness of the following"); - if (gch->incremental_collection_will_fail()) { - if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" %s: collect because incremental collection will fail ", - short_name()); - } - return true; - } - if (!_cmsSpace->adaptive_freelists() && - _cmsSpace->linearAllocationWouldFail()) { + if (_cmsSpace->should_concurrent_collect()) { if (PrintGCDetails && Verbose) { - gclog_or_tty->print(" %s: collect because of linAB ", + gclog_or_tty->print(" %s: collect because cmsSpace says so ", short_name()); } return true; @@ -1970,8 +1991,9 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) { "Should have been NULL'd before baton was passed"); reset(false /* == !asynch */); _cmsGen->reset_after_compaction(); + _concurrent_cycles_since_last_unload = 0; - if (verifying() && !cms_should_unload_classes()) { + if (verifying() && !should_unload_classes()) { perm_gen_verify_bit_map()->clear_all(); } @@ -2098,6 +2120,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) { { bool safepoint_check = Mutex::_no_safepoint_check_flag; MutexLockerEx hl(Heap_lock, safepoint_check); + FreelistLocker fll(this); MutexLockerEx x(CGC_lock, safepoint_check); if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) { // The foreground collector is active or we're @@ -2112,13 +2135,9 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) { // a new cycle. clear_expansion_cause(); } - _unloaded_classes_last_cycle = cms_should_unload_classes(); // ... from last cycle - // This controls class unloading in response to an explicit gc request. - // If ExplicitGCInvokesConcurrentAndUnloadsClasses is set, then - // we will unload classes even if CMSClassUnloadingEnabled is not set. - // See CR 6541037 and related CRs. - _unload_classes = _full_gc_requested // ... for this cycle - && ExplicitGCInvokesConcurrentAndUnloadsClasses; + // Decide if we want to enable class unloading as part of the + // ensuing concurrent GC cycle. + update_should_unload_classes(); _full_gc_requested = false; // acks all outstanding full gc requests // Signal that we are about to start a collection gch->increment_total_full_collections(); // ... starting a collection cycle @@ -3047,21 +3066,62 @@ void CMSCollector::verify_overflow_empty() const { } #endif // PRODUCT +// Decide if we want to enable class unloading as part of the +// ensuing concurrent GC cycle. We will collect the perm gen and +// unload classes if it's the case that: +// (1) an explicit gc request has been made and the flag +// ExplicitGCInvokesConcurrentAndUnloadsClasses is set, OR +// (2) (a) class unloading is enabled at the command line, and +// (b) (i) perm gen threshold has been crossed, or +// (ii) old gen is getting really full, or +// (iii) the previous N CMS collections did not collect the +// perm gen +// NOTE: Provided there is no change in the state of the heap between +// calls to this method, it should have idempotent results. Moreover, +// its results should be monotonically increasing (i.e. going from 0 to 1, +// but not 1 to 0) between successive calls between which the heap was +// not collected. For the implementation below, it must thus rely on +// the property that concurrent_cycles_since_last_unload() +// will not decrease unless a collection cycle happened and that +// _permGen->should_concurrent_collect() and _cmsGen->is_too_full() are +// themselves also monotonic in that sense. See check_monotonicity() +// below. +bool CMSCollector::update_should_unload_classes() { + _should_unload_classes = false; + // Condition 1 above + if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) { + _should_unload_classes = true; + } else if (CMSClassUnloadingEnabled) { // Condition 2.a above + // Disjuncts 2.b.(i,ii,iii) above + _should_unload_classes = (concurrent_cycles_since_last_unload() >= + CMSClassUnloadingMaxInterval) + || _permGen->should_concurrent_collect() + || _cmsGen->is_too_full(); + } + return _should_unload_classes; +} + +bool ConcurrentMarkSweepGeneration::is_too_full() const { + bool res = should_concurrent_collect(); + res = res && (occupancy() > (double)CMSIsTooFullPercentage/100.0); + return res; +} + void CMSCollector::setup_cms_unloading_and_verification_state() { const bool should_verify = VerifyBeforeGC || VerifyAfterGC || VerifyDuringGC || VerifyBeforeExit; const int rso = SharedHeap::SO_Symbols | SharedHeap::SO_Strings | SharedHeap::SO_CodeCache; - if (cms_should_unload_classes()) { // Should unload classes this cycle + if (should_unload_classes()) { // Should unload classes this cycle remove_root_scanning_option(rso); // Shrink the root set appropriately set_verifying(should_verify); // Set verification state for this cycle return; // Nothing else needs to be done at this time } // Not unloading classes this cycle - assert(!cms_should_unload_classes(), "Inconsitency!"); - if ((!verifying() || cms_unloaded_classes_last_cycle()) && should_verify) { + assert(!should_unload_classes(), "Inconsitency!"); + if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) { // We were not verifying, or we _were_ unloading classes in the last cycle, // AND some verification options are enabled this cycle; in this case, // we must make sure that the deadness map is allocated if not already so, @@ -4693,7 +4753,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch, GenCollectedHeap* gch = GenCollectedHeap::heap(); - if (cms_should_unload_classes()) { + if (should_unload_classes()) { CodeCache::gc_prologue(); } assert(haveFreelistLocks(), "must have free list locks"); @@ -4753,7 +4813,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch, verify_work_stacks_empty(); verify_overflow_empty(); - if (cms_should_unload_classes()) { + if (should_unload_classes()) { CodeCache::gc_epilogue(); } @@ -5623,7 +5683,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) { verify_work_stacks_empty(); } - if (cms_should_unload_classes()) { + if (should_unload_classes()) { { TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty); @@ -5726,7 +5786,7 @@ void CMSCollector::sweep(bool asynch) { // this cycle, we preserve the perm gen object "deadness" information // in the perm_gen_verify_bit_map. In order to do that we traverse // all blocks in perm gen and mark all dead objects. - if (verifying() && !cms_should_unload_classes()) { + if (verifying() && !should_unload_classes()) { assert(perm_gen_verify_bit_map()->sizeInBits() != 0, "Should have already been allocated"); MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(), @@ -5753,7 +5813,7 @@ void CMSCollector::sweep(bool asynch) { } // Now repeat for perm gen - if (cms_should_unload_classes()) { + if (should_unload_classes()) { CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(), bitMapLock()); sweepWork(_permGen, asynch); @@ -5775,7 +5835,7 @@ void CMSCollector::sweep(bool asynch) { // already have needed locks sweepWork(_cmsGen, asynch); - if (cms_should_unload_classes()) { + if (should_unload_classes()) { sweepWork(_permGen, asynch); } // Update heap occupancy information which is used as @@ -5937,6 +5997,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen, } gen->cmsSpace()->sweep_completed(); gen->cmsSpace()->endSweepFLCensus(sweepCount()); + if (should_unload_classes()) { // unloaded classes this cycle, + _concurrent_cycles_since_last_unload = 0; // ... reset count + } else { // did not unload classes, + _concurrent_cycles_since_last_unload++; // ... increment count + } } // Reset CMS data structures (for now just the marking bit map) @@ -7194,7 +7259,7 @@ PushOrMarkClosure::PushOrMarkClosure(CMSCollector* collector, _revisitStack(revisitStack), _finger(finger), _parent(parent), - _should_remember_klasses(collector->cms_should_unload_classes()) + _should_remember_klasses(collector->should_unload_classes()) { } Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector, @@ -7217,7 +7282,7 @@ Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector, _finger(finger), _global_finger_addr(global_finger_addr), _parent(parent), - _should_remember_klasses(collector->cms_should_unload_classes()) + _should_remember_klasses(collector->should_unload_classes()) { } @@ -7360,7 +7425,7 @@ PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector, _mark_stack(mark_stack), _revisit_stack(revisit_stack), _concurrent_precleaning(concurrent_precleaning), - _should_remember_klasses(collector->cms_should_unload_classes()) + _should_remember_klasses(collector->should_unload_classes()) { assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); } @@ -7422,7 +7487,7 @@ Par_PushAndMarkClosure::Par_PushAndMarkClosure(CMSCollector* collector, _bit_map(bit_map), _work_queue(work_queue), _revisit_stack(revisit_stack), - _should_remember_klasses(collector->cms_should_unload_classes()) + _should_remember_klasses(collector->should_unload_classes()) { assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL"); } @@ -7944,7 +8009,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { #ifdef DEBUG if (oop(addr)->klass() != NULL && - ( !_collector->cms_should_unload_classes() + ( !_collector->should_unload_classes() || oop(addr)->is_parsable())) { // Ignore mark word because we are running concurrent with mutators assert(oop(addr)->is_oop(true), "live block should be an oop"); @@ -7957,7 +8022,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { } else { // This should be an initialized object that's alive. assert(oop(addr)->klass() != NULL && - (!_collector->cms_should_unload_classes() + (!_collector->should_unload_classes() || oop(addr)->is_parsable()), "Should be an initialized object"); // Ignore mark word because we are running concurrent with mutators diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index f4f790eba..9f05caf72 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -535,13 +535,16 @@ class CMSCollector: public CHeapObj { // In support of ExplicitGCInvokesConcurrent static bool _full_gc_requested; unsigned int _collection_count_start; + // Should we unload classes this concurrent cycle? - // Set in response to a concurrent full gc request. - bool _unload_classes; - bool _unloaded_classes_last_cycle; + bool _should_unload_classes; + unsigned int _concurrent_cycles_since_last_unload; + unsigned int concurrent_cycles_since_last_unload() const { + return _concurrent_cycles_since_last_unload; + } // Did we (allow) unload classes in the previous concurrent cycle? - bool cms_unloaded_classes_last_cycle() const { - return _unloaded_classes_last_cycle || CMSClassUnloadingEnabled; + bool unloaded_classes_last_cycle() const { + return concurrent_cycles_since_last_unload() == 0; } // Verification support @@ -651,8 +654,6 @@ class CMSCollector: public CHeapObj { // number of full gc's since the last concurrent gc. uint _full_gcs_since_conc_gc; - // if occupancy exceeds this, start a new gc cycle - double _initiatingOccupancy; // occupancy used for bootstrapping stats double _bootstrap_occupancy; @@ -825,7 +826,6 @@ class CMSCollector: public CHeapObj { Mutex* bitMapLock() const { return _markBitMap.lock(); } static CollectorState abstract_state() { return _collectorState; } - double initiatingOccupancy() const { return _initiatingOccupancy; } bool should_abort_preclean() const; // Whether preclean should be aborted. size_t get_eden_used() const; @@ -849,11 +849,10 @@ class CMSCollector: public CHeapObj { // In support of ExplicitGCInvokesConcurrent static void request_full_gc(unsigned int full_gc_count); // Should we unload classes in a particular concurrent cycle? - bool cms_should_unload_classes() const { - assert(!_unload_classes || ExplicitGCInvokesConcurrentAndUnloadsClasses, - "Inconsistency; see CR 6541037"); - return _unload_classes || CMSClassUnloadingEnabled; + bool should_unload_classes() const { + return _should_unload_classes; } + bool update_should_unload_classes(); void direct_allocated(HeapWord* start, size_t size); @@ -1022,6 +1021,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { _incremental_collection_failed = false; } + // accessors + void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;} + CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; } + private: // For parallel young-gen GC support. CMSParGCThreadState** _par_gc_thread_states; @@ -1029,10 +1032,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { // Reason generation was expanded CMSExpansionCause::Cause _expansion_cause; - // accessors - void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;} - CMSExpansionCause::Cause expansion_cause() { return _expansion_cause; } - // In support of MinChunkSize being larger than min object size const double _dilatation_factor; @@ -1045,6 +1044,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { CollectionTypes _debug_collection_type; + // Fraction of current occupancy at which to start a CMS collection which + // will collect this generation (at least). + double _initiating_occupancy; + protected: // Grow generation by specified size (returns false if unable to grow) bool grow_by(size_t bytes); @@ -1060,6 +1063,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { // space. size_t max_available() const; + // getter and initializer for _initiating_occupancy field. + double initiating_occupancy() const { return _initiating_occupancy; } + void init_initiating_occupancy(intx io, intx tr); + public: ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, int level, CardTableRS* ct, @@ -1103,7 +1110,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { size_t capacity() const; size_t used() const; size_t free() const; - double occupancy() { return ((double)used())/((double)capacity()); } + double occupancy() const { return ((double)used())/((double)capacity()); } size_t contiguous_available() const; size_t unsafe_max_alloc_nogc() const; @@ -1158,8 +1165,8 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { bool younger_handles_promotion_failure) const; bool should_collect(bool full, size_t size, bool tlab); - // XXXPERM - bool shouldConcurrentCollect(double initiatingOccupancy); // XXXPERM + virtual bool should_concurrent_collect() const; + virtual bool is_too_full() const; void collect(bool full, bool clear_all_soft_refs, size_t size, diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp index c151fab33..8dd2ca4ab 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp @@ -267,7 +267,7 @@ inline bool CMSCollector::is_dead_obj(oop obj) const { (_permGen->cmsSpace()->is_in_reserved(addr) && _permGen->cmsSpace()->block_is_obj(addr)), "must be object"); - return cms_should_unload_classes() && + return should_unload_classes() && _collectorState == Sweeping && !_markBitMap.isMarked(addr); } diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index 67cb3285d..3b09dc5e7 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -1319,6 +1319,10 @@ class CommandLineFlags { product(bool, CMSClassUnloadingEnabled, false, \ "Whether class unloading enabled when using CMS GC") \ \ + product(uintx, CMSClassUnloadingMaxInterval, 0, \ + "When CMS class unloading is enabled, the maximum CMS cycle count"\ + " for which classes may not be unloaded") \ + \ product(bool, CMSCompactWhenClearAllSoftRefs, true, \ "Compact when asked to collect CMS gen with clear_all_soft_refs") \ \ @@ -1504,17 +1508,30 @@ class CommandLineFlags { "Percentage of MinHeapFreeRatio in CMS generation that is " \ " allocated before a CMS collection cycle commences") \ \ - product(intx, CMSBootstrapOccupancy, 50, \ + product(intx, CMSTriggerPermRatio, 80, \ + "Percentage of MinHeapFreeRatio in the CMS perm generation that" \ + " is allocated before a CMS collection cycle commences, that " \ + " also collects the perm generation") \ + \ + product(uintx, CMSBootstrapOccupancy, 50, \ "Percentage CMS generation occupancy at which to " \ " initiate CMS collection for bootstrapping collection stats") \ \ product(intx, CMSInitiatingOccupancyFraction, -1, \ "Percentage CMS generation occupancy to start a CMS collection " \ - " cycle (A negative value means that CMSTirggerRatio is used)") \ + " cycle (A negative value means that CMSTriggerRatio is used)") \ + \ + product(intx, CMSInitiatingPermOccupancyFraction, -1, \ + "Percentage CMS perm generation occupancy to start a CMScollection"\ + " cycle (A negative value means that CMSTriggerPermRatio is used)")\ \ product(bool, UseCMSInitiatingOccupancyOnly, false, \ "Only use occupancy as a crierion for starting a CMS collection") \ \ + product(intx, CMSIsTooFullPercentage, 98, \ + "An absolute ceiling above which CMS will always consider the" \ + " perm gen ripe for collection") \ + \ develop(bool, CMSTestInFreeList, false, \ "Check if the coalesced range is already in the " \ "free lists as claimed.") \ -- GitLab