--- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2010-03-10 14:49:33.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2010-03-10 14:49:32.000000000 -0800 @@ -959,3 +959,44 @@ } } #endif + +bool ParallelScavengeHeap::try_to_shrink_by_free_ratio(bool isFullGC) { + if (MaxHeapFreeRatio >= 100) { + // nothing to do in this case + return false; + } + + size_t capacity = old_gen()->capacity_in_bytes() + young_gen()->capacity_in_bytes(); + size_t used = old_gen()->used_in_bytes() + young_gen()->used_in_bytes(); + size_t init_size = old_gen()->init_gen_size() + young_gen()->init_gen_size(); + const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; + const double minimum_used_percentage = 1.0 - maximum_free_percentage; + const double max_tmp = used / minimum_used_percentage; + size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); + maximum_desired_capacity = MAX2(maximum_desired_capacity, init_size); + + if (PrintGC && Verbose) { + const double free_ratio = 1.0 - (double) used / capacity; + gclog_or_tty->print("Shrink by free ratio: "); + gclog_or_tty->print("capacity : " SIZE_FORMAT ", ", capacity); + gclog_or_tty->print("used : " SIZE_FORMAT ", ", used); + gclog_or_tty->print_cr("free ratio : %f.2", free_ratio); + } + + size_t free_bytes = capacity - used; + if (capacity > maximum_desired_capacity && free_bytes > 0) { + size_t young_gen_free_bytes = young_gen()->capacity_in_bytes() - young_gen()->used_in_bytes(); + size_t old_gen_free_bytes = old_gen()->capacity_in_bytes() - old_gen()->used_in_bytes(); + size_t shrink_bytes = capacity - maximum_desired_capacity; + if (isFullGC) { + size_t old_gen_shrink_bytes = + (size_t) (shrink_bytes * ((double) old_gen_free_bytes / free_bytes)); + old_gen()->try_to_shrink_by(old_gen_shrink_bytes); + } + size_t young_gen_shrink_bytes = + (size_t) (shrink_bytes * ((double) young_gen_free_bytes / free_bytes)); + young_gen()->try_to_shrink_by(young_gen_shrink_bytes); + return true; + } + return false; +} --- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2010-03-10 14:49:34.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2010-03-10 14:49:33.000000000 -0800 @@ -242,6 +242,9 @@ // Mangle the unused parts of all spaces in the heap void gen_mangle_unused_area() PRODUCT_RETURN; + // Try to shrink the heap based on the free ratio + bool try_to_shrink_by_free_ratio(bool isFullGC); + // Call these in sequential code around the processing of strong roots. class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope { public: --- old/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp 2010-03-10 14:49:34.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp 2010-03-10 14:49:34.000000000 -0800 @@ -239,7 +239,15 @@ // Let the size policy know we're done size_policy->major_collection_end(old_gen->used_in_bytes(), gc_cause); - if (UseAdaptiveSizePolicy) { + bool free_ratio_in_effect = false; + if ((UseFreeRatioForParallelGC || + (UseFreeRatioOnlyInSystemGCForParallelGC && + gc_cause == GCCause::_java_lang_system_gc))) { + ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + free_ratio_in_effect = heap->try_to_shrink_by_free_ratio(true); + } + + if (!free_ratio_in_effect && UseAdaptiveSizePolicy) { if (PrintAdaptiveSizePolicy) { gclog_or_tty->print("AdaptiveSizeStart: "); --- old/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp 2010-03-10 14:49:35.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp 2010-03-10 14:49:35.000000000 -0800 @@ -308,16 +308,16 @@ size_t size = align_size_down(bytes, virtual_space()->alignment()); if (size > 0) { assert_lock_strong(ExpandHeap_lock); - virtual_space()->shrink_by(bytes); + virtual_space()->shrink_by(size); post_resize(); if (Verbose && PrintGC) { size_t new_mem_size = virtual_space()->committed_size(); - size_t old_mem_size = new_mem_size + bytes; + size_t old_mem_size = new_mem_size + size; gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); + name(), old_mem_size/K, size/K, new_mem_size/K); } } } @@ -497,3 +497,26 @@ object_space()->set_top_for_allocations(); } #endif + +void PSOldGen::try_to_shrink_by(size_t shrink_bytes) { + if (shrink_bytes < MinHeapDeltaBytes || + capacity_in_bytes() - shrink_bytes < _init_gen_size) { + return; + } + + if (PrintGC) { + gclog_or_tty->print_cr(" Resizing old gen. shrink_bytes=%d", shrink_bytes); + gclog_or_tty->print("BEFORE: Old Gen: "); + gclog_or_tty->print("capacity : " SIZE_FORMAT ", ", capacity_in_bytes()); + gclog_or_tty->print_cr("used : " SIZE_FORMAT ", " , used_in_bytes()); + } + + MutexLocker x(ExpandHeap_lock); + shrink(shrink_bytes); + + if (PrintGC) { + gclog_or_tty->print("AFTER: Old Gen: "); + gclog_or_tty->print("capacity : " SIZE_FORMAT ", ", capacity_in_bytes()); + gclog_or_tty->print_cr("used : " SIZE_FORMAT ", " , used_in_bytes()); + } +} --- old/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp 2010-03-10 14:49:36.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psOldGen.hpp 2010-03-10 14:49:36.000000000 -0800 @@ -106,6 +106,7 @@ MemRegion reserved() const { return _reserved; } virtual size_t max_gen_size() { return _max_gen_size; } size_t min_gen_size() { return _min_gen_size; } + size_t init_gen_size() { return _init_gen_size; } // Returns limit on the maximum size of the generation. This // is the same as _max_gen_size for PSOldGen but need not be @@ -189,4 +190,6 @@ // Debugging support // Save the tops of all spaces for later use during mangling. void record_spaces_top() PRODUCT_RETURN; + + void try_to_shrink_by(size_t shrink_bytes); }; --- old/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp 2010-03-10 14:49:37.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp 2010-03-10 14:49:36.000000000 -0800 @@ -2073,7 +2073,15 @@ // Let the size policy know we're done size_policy->major_collection_end(old_gen->used_in_bytes(), gc_cause); - if (UseAdaptiveSizePolicy) { + bool free_ratio_in_effect = false; + if ((UseFreeRatioForParallelGC || + (UseFreeRatioOnlyInSystemGCForParallelGC && + gc_cause == GCCause::_java_lang_system_gc))) { + ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + free_ratio_in_effect = heap->try_to_shrink_by_free_ratio(true); + } + + if (!free_ratio_in_effect && UseAdaptiveSizePolicy) { if (PrintAdaptiveSizePolicy) { gclog_or_tty->print("AdaptiveSizeStart: "); gclog_or_tty->stamp(); --- old/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp 2010-03-10 14:49:37.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp 2010-03-10 14:49:37.000000000 -0800 @@ -447,7 +447,15 @@ size_t promoted = old_gen->used_in_bytes() - old_gen_used_before; size_policy->update_averages(_survivor_overflow, survived, promoted); - if (UseAdaptiveSizePolicy) { + bool free_ratio_in_effect = false; + if ((UseFreeRatioForParallelGC || + (UseFreeRatioOnlyInSystemGCForParallelGC && + gc_cause == GCCause::_java_lang_system_gc))) { + ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); + free_ratio_in_effect = heap->try_to_shrink_by_free_ratio(false); + } + + if (!free_ratio_in_effect && UseAdaptiveSizePolicy) { // Calculate the new survivor size and tenuring threshold if (PrintAdaptiveSizePolicy) { --- old/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp 2010-03-10 14:49:38.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp 2010-03-10 14:49:38.000000000 -0800 @@ -163,6 +163,9 @@ set_space_boundaries(eden_size, survivor_size); space_invariants(); + _init_survivor_size = survivor_size; + _init_eden_size = eden_size; + if (UsePerfData) { _eden_counters->update_capacity(); _from_counters->update_capacity(); @@ -949,3 +952,76 @@ to_space()->set_top_for_allocations(); } #endif + +void PSYoungGen::try_to_shrink_by(size_t shrink_bytes) { + size_t free_bytes = capacity_in_bytes() - used_in_bytes(); + if (free_bytes == 0) { + // cannot shrink + return; + } + size_t eden_free_bytes = eden_space()->capacity_in_bytes() - eden_space()->used_in_bytes(); + size_t survivor_free_bytes = from_space()->capacity_in_bytes() - from_space()->used_in_bytes(); + size_t eden_shrink_bytes = + (size_t) (shrink_bytes * ((double) eden_free_bytes / free_bytes)); + size_t survivor_shrink_bytes = + (size_t) (shrink_bytes * ((double) survivor_free_bytes / free_bytes)); + + // Don't shrink unless it's significant + if (eden_shrink_bytes < MinHeapDeltaBytes) { + eden_shrink_bytes = 0; + } + if (survivor_shrink_bytes < MinHeapDeltaBytes) { + survivor_shrink_bytes = 0; + } + + if (eden_shrink_bytes == 0 && survivor_shrink_bytes == 0) { + return; // no change, so return now + } + + size_t eden_desired_capacity = + eden_space()->capacity_in_bytes() - eden_shrink_bytes; + eden_desired_capacity = MAX2(eden_desired_capacity, _init_eden_size); + assert(eden_space()->used_in_bytes() <= eden_desired_capacity, "sanity check"); + eden_desired_capacity = align_size_down(eden_desired_capacity, + virtual_space()->alignment()); + + size_t survivor_desired_capacity = + from_space()->capacity_in_bytes() - survivor_shrink_bytes; + survivor_desired_capacity = MAX2(survivor_desired_capacity, _init_survivor_size); + assert(from_space()->used_in_bytes() <= survivor_desired_capacity, "sanity check"); + survivor_desired_capacity = align_size_down(survivor_desired_capacity, + virtual_space()->alignment()); + + if (eden_desired_capacity == eden_space()->capacity_in_bytes() + && survivor_desired_capacity == from_space()->capacity_in_bytes()) { + return; // no change, so return now + } + + if (PrintGC) { + gclog_or_tty->print_cr(" Resizing young gen. shrink_bytes=%d,%d", + eden_shrink_bytes, survivor_shrink_bytes); + gclog_or_tty->print("BEFORE: Young Gen: "); + gclog_or_tty->print("eden capacity : " SIZE_FORMAT ", ", + eden_space()->capacity_in_bytes()); + gclog_or_tty->print("eden used : " SIZE_FORMAT ", " , + eden_space()->used_in_bytes()); + gclog_or_tty->print("survivor capacity : " SIZE_FORMAT ", ", + from_space()->capacity_in_bytes()); + gclog_or_tty->print_cr("survivor used : " SIZE_FORMAT ", " , + from_space()->used_in_bytes()); + } + + resize(eden_desired_capacity, survivor_desired_capacity); + + if (PrintGC) { + gclog_or_tty->print("AFTER: Young Gen: "); + gclog_or_tty->print("eden capacity : " SIZE_FORMAT ", ", + eden_space()->capacity_in_bytes()); + gclog_or_tty->print("eden used : " SIZE_FORMAT ", " , + eden_space()->used_in_bytes()); + gclog_or_tty->print("survivor capacity : " SIZE_FORMAT ", ", + from_space()->capacity_in_bytes()); + gclog_or_tty->print_cr("survivor used : " SIZE_FORMAT ", " , + from_space()->used_in_bytes()); + } +} --- old/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp 2010-03-10 14:49:39.000000000 -0800 +++ new/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.hpp 2010-03-10 14:49:39.000000000 -0800 @@ -49,6 +49,9 @@ const size_t _min_gen_size; const size_t _max_gen_size; + size_t _init_survivor_size; + size_t _init_eden_size; + // Performance counters PSGenerationCounters* _gen_counters; SpaceCounters* _eden_counters; @@ -91,6 +94,8 @@ virtual void initialize(ReservedSpace rs, size_t alignment); virtual void initialize_virtual_space(ReservedSpace rs, size_t alignment); + size_t init_gen_size() { return _init_gen_size; } + MemRegion reserved() const { return _reserved; } bool is_in(const void* p) const { @@ -187,4 +192,6 @@ MemRegion s2MR) PRODUCT_RETURN; void record_spaces_top() PRODUCT_RETURN; + + void try_to_shrink_by(size_t shrink_bytes); }; --- old/src/share/vm/runtime/globals.hpp 2010-03-10 14:49:40.000000000 -0800 +++ new/src/share/vm/runtime/globals.hpp 2010-03-10 14:49:39.000000000 -0800 @@ -3070,6 +3070,13 @@ "how many entries we'll try to leave on the stack during " \ "parallel GC") \ \ + product(bool, UseFreeRatioForParallelGC, false, \ + "If true, override the adaptive size policy with the free ratios "\ + "(MaxHeapFreeRatio and MinHeapFreeRatio) when applicable.") \ + \ + product(bool, UseFreeRatioOnlyInSystemGCForParallelGC, false, \ + "Like UseFreeRatioForParallelGC except only for System.gc()") \ + \ /* stack parameters */ \ product_pd(intx, StackYellowPages, \ "Number of yellow zone (recoverable overflows) pages") \