--- old/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp 2013-10-25 15:32:34.000000000 +0200 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp 2013-10-25 15:32:33.000000000 +0200 @@ -47,10 +47,6 @@ // ConcurrentMarkSweepPolicy methods // -ConcurrentMarkSweepPolicy::ConcurrentMarkSweepPolicy() { - initialize_all(); -} - void ConcurrentMarkSweepPolicy::initialize_generations() { _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL); if (_generations == NULL) --- old/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp 2013-10-25 15:32:34.000000000 +0200 +++ new/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp 2013-10-25 15:32:34.000000000 +0200 @@ -32,7 +32,7 @@ void initialize_generations(); public: - ConcurrentMarkSweepPolicy(); + ConcurrentMarkSweepPolicy() {} ConcurrentMarkSweepPolicy* as_concurrent_mark_sweep_policy() { return this; } --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-10-25 15:32:35.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-10-25 15:32:35.000000000 +0200 @@ -2008,7 +2008,7 @@ size_t init_byte_size = collector_policy()->initial_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size(); - size_t heap_alignment = collector_policy()->max_alignment(); + size_t heap_alignment = collector_policy()->heap_alignment(); // Ensure that the sizes are properly aligned. Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); @@ -2186,6 +2186,10 @@ return JNI_OK; } +size_t G1CollectedHeap::conservative_max_heap_alignment() { + return HeapRegion::max_region_size(); +} + void G1CollectedHeap::ref_processing_init() { // Reference processing in G1 currently works as follows: // --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2013-10-25 15:32:35.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2013-10-25 15:32:35.000000000 +0200 @@ -1092,9 +1092,7 @@ jint initialize(); // Return the (conservative) maximum heap alignment for any G1 heap - static size_t conservative_max_heap_alignment() { - return HeapRegion::max_region_size(); - } + static size_t conservative_max_heap_alignment(); // Initialize weak reference processing. virtual void ref_processing_init(); --- old/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp 2013-10-25 15:32:36.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp 2013-10-25 15:32:36.000000000 +0200 @@ -313,27 +313,38 @@ // for the first time during initialization. _reserve_regions = 0; - initialize_all(); _collectionSetChooser = new CollectionSetChooser(); - _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags } -void G1CollectorPolicy::initialize_flags() { - _min_alignment = HeapRegion::GrainBytes; +void G1CollectorPolicy::initialize_alignments() { + _space_alignment = HeapRegion::GrainBytes; size_t card_table_alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - _max_alignment = MAX3(card_table_alignment, _min_alignment, page_size); + _heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size); +} + +void G1CollectorPolicy::initialize_flags() { + if (G1HeapRegionSize != HeapRegion::GrainBytes) { + FLAG_SET_ERGO(uintx, G1HeapRegionSize, HeapRegion::GrainBytes); + } + if (SurvivorRatio < 1) { vm_exit_during_initialization("Invalid survivor ratio specified"); } CollectorPolicy::initialize_flags(); + _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags } -G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true) { - assert(G1NewSizePercent <= G1MaxNewSizePercent, "Min larger than max"); - assert(G1NewSizePercent > 0 && G1NewSizePercent < 100, "Min out of bounds"); - assert(G1MaxNewSizePercent > 0 && G1MaxNewSizePercent < 100, "Max out of bounds"); +void G1CollectorPolicy::post_heap_initialize() { + uintx max_regions = G1CollectedHeap::heap()->max_regions(); + size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes; + if (max_young_size != MaxNewSize) { + FLAG_SET_ERGO(uintx, MaxNewSize, max_young_size); + } +} +G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), + _min_desired_young_length(0), _max_desired_young_length(0) { if (FLAG_IS_CMDLINE(NewRatio)) { if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); @@ -378,34 +389,48 @@ return MAX2(1U, default_value); } -void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { - assert(new_number_of_heap_regions > 0, "Heap must be initialized"); +void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) { + assert(number_of_heap_regions > 0, "Heap must be initialized"); switch (_sizer_kind) { case SizerDefaults: - _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); - _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *max_young_length = calculate_default_max_length(number_of_heap_regions); break; case SizerNewSizeOnly: - _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); - _max_desired_young_length = MAX2(_min_desired_young_length, _max_desired_young_length); + *max_young_length = calculate_default_max_length(number_of_heap_regions); + *max_young_length = MAX2(*min_young_length, *max_young_length); break; case SizerMaxNewSizeOnly: - _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); - _min_desired_young_length = MIN2(_min_desired_young_length, _max_desired_young_length); + *min_young_length = calculate_default_min_length(number_of_heap_regions); + *min_young_length = MIN2(*min_young_length, *max_young_length); break; case SizerMaxAndNewSize: // Do nothing. Values set on the command line, don't update them at runtime. break; case SizerNewRatio: - _min_desired_young_length = new_number_of_heap_regions / (NewRatio + 1); - _max_desired_young_length = _min_desired_young_length; + *min_young_length = number_of_heap_regions / (NewRatio + 1); + *max_young_length = *min_young_length; break; default: ShouldNotReachHere(); } - assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); + assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values"); +} + +uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) { + // We need to pass the desired values because recalculation may not update these + // values in some cases. + uint temp = _min_desired_young_length; + uint result = _max_desired_young_length; + recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); + return result; +} + +void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { + recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, + &_max_desired_young_length); } void G1CollectorPolicy::init() { --- old/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp 2013-10-25 15:32:37.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp 2013-10-25 15:32:36.000000000 +0200 @@ -136,8 +136,16 @@ uint calculate_default_min_length(uint new_number_of_heap_regions); uint calculate_default_max_length(uint new_number_of_heap_regions); + // Update the given values for minimum and maximum young gen length in regions + // given the number of heap regions depending on the kind of sizing algorithm. + void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length); + public: G1YoungGenSizer(); + // Calculate the maximum length of the young gen given the number of regions + // depending on the sizing algorithm. + uint max_young_length(uint number_of_heap_regions); + void heap_size_changed(uint new_number_of_heap_regions); uint min_desired_young_length() { return _min_desired_young_length; @@ -165,13 +173,9 @@ G1MMUTracker* _mmu_tracker; + void initialize_alignments(); void initialize_flags(); - void initialize_all() { - initialize_flags(); - initialize_size_info(); - } - CollectionSetChooser* _collectionSetChooser; double _full_collection_start_sec; @@ -931,6 +935,7 @@ // Calculates survivor space parameters. void update_survivors_policy(); + virtual void post_heap_initialize(); }; // This should move to some place more general... --- old/src/share/vm/gc_implementation/g1/heapRegion.cpp 2013-10-25 15:32:37.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/heapRegion.cpp 2013-10-25 15:32:37.000000000 +0200 @@ -174,11 +174,6 @@ region_size = MAX_REGION_SIZE; } - if (region_size != G1HeapRegionSize) { - // Update the flag to make sure that PrintFlagsFinal logs the correct value - FLAG_SET_ERGO(uintx, G1HeapRegionSize, region_size); - } - // And recalculate the log. region_size_log = log2_long((jlong) region_size); --- old/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp 2013-10-25 15:32:38.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp 2013-10-25 15:32:37.000000000 +0200 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc_implementation/parallelScavenge/adjoiningGenerations.hpp" #include "gc_implementation/parallelScavenge/adjoiningVirtualSpaces.hpp" +#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" // If boundary moving is being used, create the young gen and old @@ -32,15 +33,17 @@ // the old behavior otherwise (with PSYoungGen and PSOldGen). AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs, - size_t init_low_byte_size, - size_t min_low_byte_size, - size_t max_low_byte_size, - size_t init_high_byte_size, - size_t min_high_byte_size, - size_t max_high_byte_size, + GenerationSizer* policy, size_t alignment) : - _virtual_spaces(old_young_rs, min_low_byte_size, - min_high_byte_size, alignment) { + _virtual_spaces(old_young_rs, policy->min_gen1_size(), + policy->min_gen0_size(), alignment) { + size_t init_low_byte_size = policy->initial_gen1_size(); + size_t min_low_byte_size = policy->min_gen1_size(); + size_t max_low_byte_size = policy->max_gen1_size(); + size_t init_high_byte_size = policy->initial_gen0_size(); + size_t min_high_byte_size = policy->min_gen0_size(); + size_t max_high_byte_size = policy->max_gen0_size(); + assert(min_low_byte_size <= init_low_byte_size && init_low_byte_size <= max_low_byte_size, "Parameter check"); assert(min_high_byte_size <= init_high_byte_size && --- old/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp 2013-10-25 15:32:38.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp 2013-10-25 15:32:38.000000000 +0200 @@ -28,6 +28,7 @@ #include "gc_implementation/parallelScavenge/adjoiningVirtualSpaces.hpp" #include "gc_implementation/parallelScavenge/asPSOldGen.hpp" #include "gc_implementation/parallelScavenge/asPSYoungGen.hpp" +#include "gc_implementation/parallelScavenge/generationSizer.hpp" // Contains two generations that both use an AdjoiningVirtualSpaces. @@ -56,14 +57,7 @@ bool request_young_gen_expansion(size_t desired_change_in_bytes); public: - AdjoiningGenerations(ReservedSpace rs, - size_t init_low_byte_size, - size_t min_low_byte_size, - size_t max_low_byte_size, - size_t init_high_byte_size, - size_t min_high_byte_size, - size_t max_high_bytes_size, - size_t alignment); + AdjoiningGenerations(ReservedSpace rs, GenerationSizer* policy, size_t alignment); // Accessors PSYoungGen* young_gen() { return _young_gen; } --- old/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp 2013-10-25 15:32:39.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp 2013-10-25 15:32:39.000000000 +0200 @@ -91,7 +91,7 @@ ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); size_t result = gen_size_limit() - virtual_space()->committed_size(); - size_t result_aligned = align_size_down(result, heap->old_gen_alignment()); + size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; } @@ -102,7 +102,7 @@ } ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t gen_alignment = heap->old_gen_alignment(); + const size_t gen_alignment = heap->generation_alignment(); PSAdaptiveSizePolicy* policy = heap->size_policy(); const size_t working_size = used_in_bytes() + (size_t) policy->avg_promoted()->padded_average(); --- old/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp 2013-10-25 15:32:39.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp 2013-10-25 15:32:39.000000000 +0200 @@ -75,7 +75,7 @@ "generation size limit is wrong"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); size_t result = gen_size_limit() - current_committed_size; - size_t result_aligned = align_size_down(result, heap->young_gen_alignment()); + size_t result_aligned = align_size_down(result, heap->generation_alignment()); return result_aligned; } @@ -92,8 +92,8 @@ if (eden_space()->is_empty()) { // Respect the minimum size for eden and for the young gen as a whole. ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t eden_alignment = heap->intra_heap_alignment(); - const size_t gen_alignment = heap->young_gen_alignment(); + const size_t eden_alignment = heap->space_alignment(); + const size_t gen_alignment = heap->generation_alignment(); assert(eden_space()->capacity_in_bytes() >= eden_alignment, "Alignment is wrong"); @@ -129,7 +129,7 @@ // to_space can be. size_t ASPSYoungGen::available_to_live() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); // Include any space that is committed but is not in eden. size_t available = pointer_delta(eden_space()->bottom(), @@ -293,7 +293,7 @@ assert(eden_start < from_start, "Cannot push into from_space"); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); --- old/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp 2013-10-25 15:32:40.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp 2013-10-25 15:32:40.000000000 +0200 @@ -31,11 +31,23 @@ // TwoGenerationCollectorPolicy. Lets reuse it! class GenerationSizer : public TwoGenerationCollectorPolicy { - public: - GenerationSizer() { - // Partial init only! - initialize_flags(); - initialize_size_info(); +private: + + void trace_gen_sizes(const char* const str) { + if (TracePageSizes) { + tty->print_cr("%s: " SIZE_FORMAT "," SIZE_FORMAT " " + SIZE_FORMAT "," SIZE_FORMAT " " + SIZE_FORMAT, + str, + _min_gen1_size / K, _max_gen1_size / K, + _min_gen0_size / K, _max_gen0_size / K, + _max_heap_byte_size / K); + } + } + + void initialize_alignments() { + _space_alignment = _gen_alignment = default_gen_alignment(); + _heap_alignment = compute_heap_alignment(); } void initialize_flags() { @@ -51,21 +63,32 @@ // default gc, which adds 2 to the ratio value. We need to // make sure the values are valid before using them. if (MinSurvivorRatio < 3) { - MinSurvivorRatio = 3; + FLAG_SET_ERGO(uintx, MinSurvivorRatio, 3); } if (InitialSurvivorRatio < 3) { - InitialSurvivorRatio = 3; + FLAG_SET_ERGO(uintx, InitialSurvivorRatio, 3); } } - size_t min_young_gen_size() { return _min_gen0_size; } - size_t young_gen_size() { return _initial_gen0_size; } - size_t max_young_gen_size() { return _max_gen0_size; } - - size_t min_old_gen_size() { return _min_gen1_size; } - size_t old_gen_size() { return _initial_gen1_size; } - size_t max_old_gen_size() { return _max_gen1_size; } + void initialize_size_info() { + trace_gen_sizes("ps heap raw"); + const size_t page_sz = os::page_size_for_region(_min_heap_byte_size, + _max_heap_byte_size, + 8); + + // Can a page size be something else than a power of two? + assert(is_power_of_2((intptr_t)page_sz), "must be a power of 2"); + size_t new_alignment = round_to(page_sz, _gen_alignment); + if (new_alignment != _gen_alignment) { + _gen_alignment = new_alignment; + // Redo everything from the start + initialize_flags(); + } + TwoGenerationCollectorPolicy::initialize_size_info(); + + trace_gen_sizes("ps heap rnd"); + } }; #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GENERATIONSIZER_HPP --- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2013-10-25 15:32:40.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2013-10-25 15:32:40.000000000 +0200 @@ -52,76 +52,20 @@ ParallelScavengeHeap* ParallelScavengeHeap::_psh = NULL; GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL; -static void trace_gen_sizes(const char* const str, - size_t og_min, size_t og_max, - size_t yg_min, size_t yg_max) -{ - if (TracePageSizes) { - tty->print_cr("%s: " SIZE_FORMAT "," SIZE_FORMAT " " - SIZE_FORMAT "," SIZE_FORMAT " " - SIZE_FORMAT, - str, - og_min / K, og_max / K, - yg_min / K, yg_max / K, - (og_max + yg_max) / K); - } -} - jint ParallelScavengeHeap::initialize() { CollectedHeap::pre_initialize(); - // Cannot be initialized until after the flags are parsed - // GenerationSizer flag_parser; + // Initialize collector policy _collector_policy = new GenerationSizer(); + _collector_policy->initialize_all(); - size_t yg_min_size = _collector_policy->min_young_gen_size(); - size_t yg_max_size = _collector_policy->max_young_gen_size(); - size_t og_min_size = _collector_policy->min_old_gen_size(); - size_t og_max_size = _collector_policy->max_old_gen_size(); - - trace_gen_sizes("ps heap raw", - og_min_size, og_max_size, - yg_min_size, yg_max_size); - - const size_t og_page_sz = os::page_size_for_region(yg_min_size + og_min_size, - yg_max_size + og_max_size, - 8); - - const size_t og_align = set_alignment(_old_gen_alignment, og_page_sz); - const size_t yg_align = set_alignment(_young_gen_alignment, og_page_sz); - - // Update sizes to reflect the selected page size(s). - // - // NEEDS_CLEANUP. The default TwoGenerationCollectorPolicy uses NewRatio; it - // should check UseAdaptiveSizePolicy. Changes from generationSizer could - // move to the common code. - yg_min_size = align_size_up(yg_min_size, yg_align); - yg_max_size = align_size_up(yg_max_size, yg_align); - size_t yg_cur_size = - align_size_up(_collector_policy->young_gen_size(), yg_align); - yg_cur_size = MAX2(yg_cur_size, yg_min_size); - - og_min_size = align_size_up(og_min_size, og_align); - // Align old gen size down to preserve specified heap size. - assert(og_align == yg_align, "sanity"); - og_max_size = align_size_down(og_max_size, og_align); - og_max_size = MAX2(og_max_size, og_min_size); - size_t og_cur_size = - align_size_down(_collector_policy->old_gen_size(), og_align); - og_cur_size = MAX2(og_cur_size, og_min_size); - - trace_gen_sizes("ps heap rnd", - og_min_size, og_max_size, - yg_min_size, yg_max_size); - - const size_t heap_size = og_max_size + yg_max_size; - - ReservedSpace heap_rs = Universe::reserve_heap(heap_size, og_align); + const size_t heap_size = _collector_policy->max_heap_byte_size(); + ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment()); MemTracker::record_virtual_memory_type((address)heap_rs.base(), mtJavaHeap); - os::trace_page_sizes("ps main", og_min_size + yg_min_size, - og_max_size + yg_max_size, og_page_sz, + os::trace_page_sizes("ps main", _collector_policy->min_heap_byte_size(), + heap_size, generation_alignment(), heap_rs.base(), heap_rs.size()); if (!heap_rs.is_reserved()) { @@ -142,12 +86,6 @@ return JNI_ENOMEM; } - // Initial young gen size is 4 Mb - // - // XXX - what about flag_parser.young_gen_size()? - const size_t init_young_size = align_size_up(4 * M, yg_align); - yg_cur_size = MAX2(MIN2(init_young_size, yg_max_size), yg_cur_size); - // Make up the generations // Calculate the maximum size that a generation can grow. This // includes growth into the other generation. Note that the @@ -157,14 +95,7 @@ double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; - _gens = new AdjoiningGenerations(heap_rs, - og_cur_size, - og_min_size, - og_max_size, - yg_cur_size, - yg_min_size, - yg_max_size, - yg_align); + _gens = new AdjoiningGenerations(heap_rs, _collector_policy, generation_alignment()); _old_gen = _gens->old_gen(); _young_gen = _gens->young_gen(); @@ -176,7 +107,7 @@ new PSAdaptiveSizePolicy(eden_capacity, initial_promo_size, young_gen()->to_space()->capacity_in_bytes(), - intra_heap_alignment(), + _collector_policy->gen_alignment(), max_gc_pause_sec, max_gc_minor_pause_sec, GCTimeRatio --- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2013-10-25 15:32:41.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2013-10-25 15:32:41.000000000 +0200 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP #define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP +#include "gc_implementation/parallelScavenge/generationSizer.hpp" #include "gc_implementation/parallelScavenge/objectStartArray.hpp" #include "gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.hpp" #include "gc_implementation/parallelScavenge/psOldGen.hpp" @@ -32,13 +33,12 @@ #include "gc_implementation/shared/gcPolicyCounters.hpp" #include "gc_implementation/shared/gcWhen.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/collectorPolicy.hpp" #include "utilities/ostream.hpp" class AdjoiningGenerations; class GCHeapSummary; class GCTaskManager; -class GenerationSizer; -class CollectorPolicy; class PSAdaptiveSizePolicy; class PSHeapSummary; @@ -54,13 +54,8 @@ static ParallelScavengeHeap* _psh; - size_t _young_gen_alignment; - size_t _old_gen_alignment; - GenerationSizer* _collector_policy; - inline size_t set_alignment(size_t& var, size_t val); - // Collection of generations that are adjacent in the // space reserved for the heap. AdjoiningGenerations* _gens; @@ -80,15 +75,7 @@ HeapWord* mem_allocate_old_gen(size_t size); public: - ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { - set_alignment(_young_gen_alignment, intra_heap_alignment()); - set_alignment(_old_gen_alignment, intra_heap_alignment()); - } - - // Return the (conservative) maximum heap alignment - static size_t conservative_max_heap_alignment() { - return GenCollectorPolicy::intra_heap_alignment(); - } + ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { } // For use by VM operations enum CollectionType { @@ -120,13 +107,15 @@ void post_initialize(); void update_counters(); - // The alignment used for the various generations. - size_t young_gen_alignment() const { return _young_gen_alignment; } - size_t old_gen_alignment() const { return _old_gen_alignment; } - - // The alignment used for eden and survivors within the young gen - // and for boundary between young gen and old gen. - size_t intra_heap_alignment() { return GenCollectorPolicy::intra_heap_alignment(); } + + // The alignment used for the various areas + size_t space_alignment() { return _collector_policy->space_alignment(); } + size_t generation_alignment() { return _collector_policy->gen_alignment(); } + + // Return the (conservative) maximum heap alignment + static size_t conservative_max_heap_alignment() { + return CollectorPolicy::compute_heap_alignment(); + } size_t capacity() const; size_t used() const; @@ -261,11 +250,4 @@ }; }; -inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val) -{ - assert(is_power_of_2((intptr_t)val), "must be a power of 2"); - var = round_to(val, intra_heap_alignment()); - return var; -} - #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PARALLELSCAVENGEHEAP_HPP --- old/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp 2013-10-25 15:32:41.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp 2013-10-25 15:32:41.000000000 +0200 @@ -37,7 +37,7 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size, - size_t intra_generation_alignment, + size_t space_alignment, double gc_pause_goal_sec, double gc_minor_pause_goal_sec, uint gc_cost_ratio) : @@ -47,7 +47,7 @@ gc_pause_goal_sec, gc_cost_ratio), _collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin / 100.0), - _intra_generation_alignment(intra_generation_alignment), + _space_alignment(space_alignment), _live_at_last_full_gc(init_promo_size), _gc_minor_pause_goal_sec(gc_minor_pause_goal_sec), _latest_major_mutator_interval_seconds(0), @@ -352,11 +352,10 @@ } // Align everything and make a final limit check - const size_t alignment = _intra_generation_alignment; - desired_eden_size = align_size_up(desired_eden_size, alignment); - desired_eden_size = MAX2(desired_eden_size, alignment); + desired_eden_size = align_size_up(desired_eden_size, _space_alignment); + desired_eden_size = MAX2(desired_eden_size, _space_alignment); - eden_limit = align_size_down(eden_limit, alignment); + eden_limit = align_size_down(eden_limit, _space_alignment); // And one last limit check, now that we've aligned things. if (desired_eden_size > eden_limit) { @@ -560,11 +559,10 @@ } // Align everything and make a final limit check - const size_t alignment = _intra_generation_alignment; - desired_promo_size = align_size_up(desired_promo_size, alignment); - desired_promo_size = MAX2(desired_promo_size, alignment); + desired_promo_size = align_size_up(desired_promo_size, _space_alignment); + desired_promo_size = MAX2(desired_promo_size, _space_alignment); - promo_limit = align_size_down(promo_limit, alignment); + promo_limit = align_size_down(promo_limit, _space_alignment); // And one last limit check, now that we've aligned things. desired_promo_size = MIN2(desired_promo_size, promo_limit); @@ -649,7 +647,7 @@ } // If the desired eden size is as small as it will get, // try to adjust the old gen size. - if (*desired_eden_size_ptr <= _intra_generation_alignment) { + if (*desired_eden_size_ptr <= _space_alignment) { // Vary the old gen size to reduce the young gen pause. This // may not be a good idea. This is just a test. if (minor_pause_old_estimator()->decrement_will_decrease()) { @@ -754,7 +752,7 @@ // If the promo size is at the minimum (i.e., the old gen // size will not actually decrease), consider changing the // young gen size. - if (*desired_promo_size_ptr < _intra_generation_alignment) { + if (*desired_promo_size_ptr < _space_alignment) { // If increasing the young generation will decrease the old gen // pause, do it. // During startup there is noise in the statistics for deciding @@ -1065,24 +1063,24 @@ size_t PSAdaptiveSizePolicy::eden_increment_aligned_up(size_t cur_eden) { size_t result = eden_increment(cur_eden, YoungGenerationSizeIncrement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_increment_aligned_down(size_t cur_eden) { size_t result = eden_increment(cur_eden); - return align_size_down(result, _intra_generation_alignment); + return align_size_down(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_increment_with_supplement_aligned_up( size_t cur_eden) { size_t result = eden_increment(cur_eden, YoungGenerationSizeIncrement + _young_gen_size_increment_supplement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_decrement_aligned_down(size_t cur_eden) { size_t eden_heap_delta = eden_decrement(cur_eden); - return align_size_down(eden_heap_delta, _intra_generation_alignment); + return align_size_down(eden_heap_delta, _space_alignment); } size_t PSAdaptiveSizePolicy::eden_decrement(size_t cur_eden) { @@ -1104,24 +1102,24 @@ size_t PSAdaptiveSizePolicy::promo_increment_aligned_up(size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_increment_aligned_down(size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement); - return align_size_down(result, _intra_generation_alignment); + return align_size_down(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_increment_with_supplement_aligned_up( size_t cur_promo) { size_t result = promo_increment(cur_promo, TenuredGenerationSizeIncrement + _old_gen_size_increment_supplement); - return align_size_up(result, _intra_generation_alignment); + return align_size_up(result, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_decrement_aligned_down(size_t cur_promo) { size_t promo_heap_delta = promo_decrement(cur_promo); - return align_size_down(promo_heap_delta, _intra_generation_alignment); + return align_size_down(promo_heap_delta, _space_alignment); } size_t PSAdaptiveSizePolicy::promo_decrement(size_t cur_promo) { @@ -1134,9 +1132,9 @@ bool is_survivor_overflow, uint tenuring_threshold, size_t survivor_limit) { - assert(survivor_limit >= _intra_generation_alignment, + assert(survivor_limit >= _space_alignment, "survivor_limit too small"); - assert((size_t)align_size_down(survivor_limit, _intra_generation_alignment) + assert((size_t)align_size_down(survivor_limit, _space_alignment) == survivor_limit, "survivor_limit not aligned"); // This method is called even if the tenuring threshold and survivor @@ -1200,8 +1198,8 @@ // We're trying to pad the survivor size as little as possible without // overflowing the survivor spaces. size_t target_size = align_size_up((size_t)_avg_survived->padded_average(), - _intra_generation_alignment); - target_size = MAX2(target_size, _intra_generation_alignment); + _space_alignment); + target_size = MAX2(target_size, _space_alignment); if (target_size > survivor_limit) { // Target size is bigger than we can handle. Let's also reduce --- old/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp 2013-10-25 15:32:42.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp 2013-10-25 15:32:42.000000000 +0200 @@ -91,7 +91,7 @@ // for making ergonomic decisions. double _latest_major_mutator_interval_seconds; - const size_t _intra_generation_alignment; // alignment for eden, survivors + const size_t _space_alignment; // alignment for eden, survivors const double _gc_minor_pause_goal_sec; // goal for maximum minor gc pause @@ -229,7 +229,7 @@ PSAdaptiveSizePolicy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size, - size_t intra_generation_alignment, + size_t space_alignment, double gc_pause_goal_sec, double gc_minor_pause_goal_sec, uint gc_time_ratio); @@ -378,7 +378,7 @@ // remain almost full anyway (top() will be near end(), but there will be a // large filler object at the bottom). const size_t sz = gen_size / MinSurvivorRatio; - const size_t alignment = _intra_generation_alignment; + const size_t alignment = _space_alignment; return sz > alignment ? align_size_down(sz, alignment) : alignment; } --- old/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp 2013-10-25 15:32:42.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp 2013-10-25 15:32:42.000000000 +0200 @@ -103,7 +103,7 @@ // Compute maximum space sizes for performance counters ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - size_t alignment = heap->intra_heap_alignment(); + size_t alignment = heap->space_alignment(); size_t size = virtual_space()->reserved_size(); size_t max_survivor_size; @@ -156,8 +156,9 @@ assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // Compute sizes - size_t alignment = heap->intra_heap_alignment(); + size_t alignment = heap->space_alignment(); size_t size = virtual_space()->committed_size(); + assert(size >= 3 * alignment, "Young space is not large enough for eden + 2 survivors"); size_t survivor_size = size / InitialSurvivorRatio; survivor_size = align_size_down(survivor_size, alignment); @@ -207,7 +208,7 @@ #ifndef PRODUCT void PSYoungGen::space_invariants() { ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); // Currently, our eden size cannot shrink to zero guarantee(eden_space()->capacity_in_bytes() >= alignment, "eden too small"); @@ -491,7 +492,7 @@ char* to_end = (char*)to_space()->end(); ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t alignment = heap->intra_heap_alignment(); + const size_t alignment = heap->space_alignment(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); @@ -840,8 +841,8 @@ size_t PSYoungGen::available_to_live() { size_t delta_in_survivor = 0; ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap(); - const size_t space_alignment = heap->intra_heap_alignment(); - const size_t gen_alignment = heap->young_gen_alignment(); + const size_t space_alignment = heap->space_alignment(); + const size_t gen_alignment = heap->generation_alignment(); MutableSpace* space_shrinking = NULL; if (from_space()->end() > to_space()->end()) { --- old/src/share/vm/gc_interface/collectedHeap.cpp 2013-10-25 15:32:43.000000000 +0200 +++ new/src/share/vm/gc_interface/collectedHeap.cpp 2013-10-25 15:32:43.000000000 +0200 @@ -469,6 +469,10 @@ fill_with_object_impl(start, words, zap); } +void CollectedHeap::post_initialize() { + collector_policy()->post_heap_initialize(); +} + HeapWord* CollectedHeap::allocate_new_tlab(size_t size) { guarantee(false, "thread-local allocation buffers not supported"); return NULL; --- old/src/share/vm/memory/collectorPolicy.cpp 2013-10-25 15:32:43.000000000 +0200 +++ new/src/share/vm/memory/collectorPolicy.cpp 2013-10-25 15:32:43.000000000 +0200 @@ -47,54 +47,110 @@ // CollectorPolicy methods. -void CollectorPolicy::initialize_flags() { - assert(_max_alignment >= _min_alignment, - err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT, - _max_alignment, _min_alignment)); - assert(_max_alignment % _min_alignment == 0, - err_msg("max_alignment: " SIZE_FORMAT " not aligned by min_alignment: " SIZE_FORMAT, - _max_alignment, _min_alignment)); - - if (MaxHeapSize < InitialHeapSize) { - vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); - } - - MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, _min_alignment); +CollectorPolicy::CollectorPolicy() : + _space_alignment(0), + _heap_alignment(0), + _initial_heap_byte_size(InitialHeapSize), + _max_heap_byte_size(MaxHeapSize), + _min_heap_byte_size(Arguments::min_heap_size()), + _max_heap_size_cmdline(false), + _size_policy(NULL), + _should_clear_all_soft_refs(false), + _all_soft_refs_clear(false) +{} + +void CollectorPolicy::assert_flags() { + assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes"); + assert(InitialHeapSize % _heap_alignment == 0, "InitialHeapSize alignment"); + assert(MaxHeapSize % _heap_alignment == 0, "MaxHeapSize alignment"); +} + +void CollectorPolicy::assert_size_info() { + assert(InitialHeapSize == _initial_heap_byte_size, "Discrepancy between InitialHeapSize flag and local storage"); + assert(MaxHeapSize == _max_heap_byte_size, "Discrepancy between MaxHeapSize flag and local storage"); + assert(_max_heap_byte_size >= _min_heap_byte_size, "Ergonomics decided on incompatible minimum and maximum heap sizes"); + assert(_initial_heap_byte_size >= _min_heap_byte_size, "Ergonomics decided on incompatible initial and minimum heap sizes"); + assert(_max_heap_byte_size >= _initial_heap_byte_size, "Ergonomics decided on incompatible initial and maximum heap sizes"); + assert(_min_heap_byte_size % _heap_alignment == 0, "min_heap_byte_size alignment"); + assert(_initial_heap_byte_size % _heap_alignment == 0, "initial_heap_byte_size alignment"); + assert(_max_heap_byte_size % _heap_alignment == 0, "max_heap_byte_size alignment"); +} + +void CollectorPolicy::initialize_alignments() { + _space_alignment = (uintx) Generation::GenGrain; + _heap_alignment = compute_heap_alignment(); } -void CollectorPolicy::initialize_size_info() { - // User inputs from -mx and ms must be aligned - _min_heap_byte_size = align_size_up(Arguments::min_heap_size(), _min_alignment); - _initial_heap_byte_size = align_size_up(InitialHeapSize, _min_alignment); - _max_heap_byte_size = align_size_up(MaxHeapSize, _max_alignment); +void CollectorPolicy::initialize_flags() { + assert(_space_alignment != 0, "Space alignment not set up properly"); + assert(_heap_alignment != 0, "Heap alignment not set up properly"); + assert(_heap_alignment >= _space_alignment, + err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment)); + assert(_heap_alignment % _space_alignment == 0, + err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment)); + + if (FLAG_IS_CMDLINE(MaxHeapSize)) { + if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { + vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size"); + } + if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) { + vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + } + _max_heap_size_cmdline = true; + } // Check heap parameter properties - if (_initial_heap_byte_size < M) { + if (InitialHeapSize < M) { vm_exit_during_initialization("Too small initial heap"); } - // Check heap parameter properties if (_min_heap_byte_size < M) { vm_exit_during_initialization("Too small minimum heap"); } - if (_initial_heap_byte_size <= NewSize) { - // make sure there is at least some room in old space - vm_exit_during_initialization("Too small initial heap for new size specified"); + + // User inputs from -Xmx and -Xms must be aligned + _min_heap_byte_size = align_size_up(_min_heap_byte_size, _heap_alignment); + uintx alignedInitialHeapSize = align_size_up(InitialHeapSize, _heap_alignment); + uintx alignedMaxHeapSize = align_size_up(MaxHeapSize, _heap_alignment); + + // Write back to flags if the values changed + if (alignedInitialHeapSize != InitialHeapSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, alignedInitialHeapSize); } - if (_max_heap_byte_size < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + if (alignedMaxHeapSize != MaxHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, alignedMaxHeapSize); } - if (_initial_heap_byte_size < _min_heap_byte_size) { + + if (FLAG_IS_CMDLINE(InitialHeapSize) && _min_heap_byte_size != 0 && + InitialHeapSize < _min_heap_byte_size) { vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified"); } - if (_max_heap_byte_size < _initial_heap_byte_size) { - vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); + if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, InitialHeapSize); + } else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, MaxHeapSize); + if (InitialHeapSize < _min_heap_byte_size) { + _min_heap_byte_size = InitialHeapSize; + } } + _initial_heap_byte_size = InitialHeapSize; + _max_heap_byte_size = MaxHeapSize; + + FLAG_SET_ERGO(uintx, MinHeapDeltaBytes, align_size_up(MinHeapDeltaBytes, _space_alignment)); + + CollectorPolicy::assert_flags(); +} + +void CollectorPolicy::initialize_size_info() { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " SIZE_FORMAT " Maximum heap " SIZE_FORMAT, _min_heap_byte_size, _initial_heap_byte_size, _max_heap_byte_size); } + + CollectorPolicy::assert_size_info(); } bool CollectorPolicy::use_should_clear_all_soft_refs(bool v) { @@ -118,7 +174,7 @@ _all_soft_refs_clear = true; } -size_t CollectorPolicy::compute_max_alignment() { +size_t CollectorPolicy::compute_heap_alignment() { // The card marking array and the offset arrays for old generations are // committed in os pages as well. Make sure they are entirely full (to // avoid partial page problems), e.g. if 512 bytes heap corresponds to 1 @@ -146,13 +202,12 @@ // GenCollectorPolicy methods. size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { - return align_size_down_bounded(base_size / (NewRatio + 1), _min_alignment); + return align_size_down_bounded(base_size / (NewRatio + 1), _gen_alignment); } size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, size_t maximum_size) { - size_t alignment = _min_alignment; - size_t max_minus = maximum_size - alignment; + size_t max_minus = maximum_size - _gen_alignment; return desired_size < max_minus ? desired_size : max_minus; } @@ -168,101 +223,183 @@ GCTimeRatio); } -void GenCollectorPolicy::initialize_flags() { - // All sizes must be multiples of the generation granularity. - _min_alignment = (uintx) Generation::GenGrain; - _max_alignment = compute_max_alignment(); +size_t GenCollectorPolicy::young_gen_size_lower_bound() { + // The young generation must be aligned and have room for eden + two survivors + return align_size_up(3 * _space_alignment, _gen_alignment); +} + +void GenCollectorPolicy::assert_flags() { + CollectorPolicy::assert_flags(); + assert(NewSize >= _min_gen0_size, "Ergonomics decided on a too small young gen size"); + assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes"); + assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young gen and heap sizes"); + assert(NewSize % _gen_alignment == 0, "NewSize alignment"); + assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % _gen_alignment == 0, "MaxNewSize alignment"); +} + +void TwoGenerationCollectorPolicy::assert_flags() { + GenCollectorPolicy::assert_flags(); + assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes"); + assert(OldSize % _gen_alignment == 0, "OldSize alignment"); +} + +void GenCollectorPolicy::assert_size_info() { + CollectorPolicy::assert_size_info(); + // GenCollectorPolicy::initialize_size_info may update the MaxNewSize + assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes"); + assert(NewSize == _initial_gen0_size, "Discrepancy between NewSize flag and local storage"); + assert(MaxNewSize == _max_gen0_size, "Discrepancy between MaxNewSize flag and local storage"); + assert(_min_gen0_size <= _initial_gen0_size, "Ergonomics decided on incompatible minimum and initial young gen sizes"); + assert(_initial_gen0_size <= _max_gen0_size, "Ergonomics decided on incompatible initial and maximum young gen sizes"); + assert(_min_gen0_size % _gen_alignment == 0, "_min_gen0_size alignment"); + assert(_initial_gen0_size % _gen_alignment == 0, "_initial_gen0_size alignment"); + assert(_max_gen0_size % _gen_alignment == 0, "_max_gen0_size alignment"); +} + +void TwoGenerationCollectorPolicy::assert_size_info() { + GenCollectorPolicy::assert_size_info(); + assert(OldSize == _initial_gen1_size, "Discrepancy between OldSize flag and local storage"); + assert(_min_gen1_size <= _initial_gen1_size, "Ergonomics decided on incompatible minimum and initial old gen sizes"); + assert(_initial_gen1_size <= _max_gen1_size, "Ergonomics decided on incompatible initial and maximum old gen sizes"); + assert(_max_gen1_size % _gen_alignment == 0, "_max_gen1_size alignment"); + assert(_initial_gen1_size % _gen_alignment == 0, "_initial_gen1_size alignment"); + assert(_max_heap_byte_size <= (_max_gen0_size + _max_gen1_size), "Total maximum heap sizes must be sum of generation maximum sizes"); +} + +void GenCollectorPolicy::initialize_alignments() { + CollectorPolicy::initialize_alignments(); + _gen_alignment = default_gen_alignment(); +} +void GenCollectorPolicy::initialize_flags() { CollectorPolicy::initialize_flags(); - // All generational heaps have a youngest gen; handle those flags here. + assert(_gen_alignment != 0, "Generation alignment not set up properly"); + assert(_heap_alignment >= _gen_alignment, + err_msg("heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment)); + assert(_gen_alignment % _space_alignment == 0, + err_msg("gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _gen_alignment, _space_alignment)); + + // All generational heaps have a youngest gen; handle those flags here + if (FLAG_IS_CMDLINE(NewSize) && FLAG_IS_CMDLINE(MaxNewSize) && NewSize > MaxNewSize) { + vm_exit_during_initialization("Initial young gen size set larger than the maximum young gen size"); + } + + // Make sure the heap is large enough for two generations + uintx smallestNewSize = young_gen_size_lower_bound(); + uintx smallestHeapSize = align_size_up(smallestNewSize + align_size_up(_space_alignment, _gen_alignment), + _heap_alignment); + if (MaxHeapSize < smallestHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, smallestHeapSize); + _max_heap_byte_size = MaxHeapSize; + } + // If needed, synchronize _min_heap_byte size and _initial_heap_byte_size + if (_min_heap_byte_size < smallestHeapSize) { + _min_heap_byte_size = smallestHeapSize; + if (InitialHeapSize < _min_heap_byte_size) { + FLAG_SET_ERGO(uintx, InitialHeapSize, smallestHeapSize); + _initial_heap_byte_size = smallestHeapSize; + } + } - // Adjust max size parameters - if (NewSize > MaxNewSize) { - MaxNewSize = NewSize; + // Now take the actual NewSize into account. We will silently increase NewSize + // if the user specified a smaller value. + smallestNewSize = MAX2(smallestNewSize, (uintx)align_size_down(NewSize, _gen_alignment)); + if (smallestNewSize != NewSize) { + FLAG_SET_ERGO(uintx, NewSize, smallestNewSize); + } + _initial_gen0_size = NewSize; + + if (!FLAG_IS_DEFAULT(MaxNewSize)) { + uintx minNewSize = MAX2(_gen_alignment, _min_gen0_size); + + if (MaxNewSize >= MaxHeapSize) { + // Make sure there is room for an old generation + uintx smallerMaxNewSize = MaxHeapSize - _gen_alignment; + if (FLAG_IS_CMDLINE(MaxNewSize)) { + warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or greater than the entire " + "heap (" SIZE_FORMAT "k). A new max generation size of " SIZE_FORMAT "k will be used.", + MaxNewSize/K, MaxHeapSize/K, smallerMaxNewSize/K); + } + FLAG_SET_ERGO(uintx, MaxNewSize, smallerMaxNewSize); + if (NewSize > MaxNewSize) { + FLAG_SET_ERGO(uintx, NewSize, MaxNewSize); + _initial_gen0_size = NewSize; + } + } else if (MaxNewSize < minNewSize) { + FLAG_SET_ERGO(uintx, MaxNewSize, minNewSize); + } else if (!is_size_aligned(MaxNewSize, _gen_alignment)) { + FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _gen_alignment)); + } + _max_gen0_size = MaxNewSize; } - NewSize = align_size_down(NewSize, _min_alignment); - MaxNewSize = align_size_down(MaxNewSize, _min_alignment); - // Check validity of heap flags - assert(NewSize % _min_alignment == 0, "eden space alignment"); - assert(MaxNewSize % _min_alignment == 0, "survivor space alignment"); - - if (NewSize < 3 * _min_alignment) { - // make sure there room for eden and two survivor spaces - vm_exit_during_initialization("Too small new size specified"); + if (NewSize > MaxNewSize) { + // At this point this should only happen if the user specifies a large NewSize or + // a small (but not too small) MaxNewSize. + if (FLAG_IS_CMDLINE(NewSize)) { + warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " + "A new generation size of " SIZE_FORMAT "k will be used.", + NewSize/K, MaxNewSize/K, MaxNewSize/K); + } + FLAG_SET_ERGO(uintx, NewSize, MaxNewSize); + _initial_gen0_size = NewSize; } if (SurvivorRatio < 1 || NewRatio < 1) { vm_exit_during_initialization("Invalid young gen ratio specified"); } + + GenCollectorPolicy::assert_flags(); } void TwoGenerationCollectorPolicy::initialize_flags() { GenCollectorPolicy::initialize_flags(); - OldSize = align_size_down(OldSize, _min_alignment); + if (!is_size_aligned(OldSize, _gen_alignment)) { + FLAG_SET_ERGO(uintx, OldSize, align_size_down(OldSize, _gen_alignment)); + } - if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) { + if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) { // NewRatio will be used later to set the young generation size so we use // it to calculate how big the heap should be based on the requested OldSize // and NewRatio. assert(NewRatio > 0, "NewRatio should have been set up earlier"); size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); - calculated_heapsize = align_size_up(calculated_heapsize, _max_alignment); - MaxHeapSize = calculated_heapsize; - InitialHeapSize = calculated_heapsize; + calculated_heapsize = align_size_up(calculated_heapsize, _heap_alignment); + FLAG_SET_ERGO(uintx, MaxHeapSize, calculated_heapsize); + _max_heap_byte_size = MaxHeapSize; + FLAG_SET_ERGO(uintx, InitialHeapSize, calculated_heapsize); + _initial_heap_byte_size = InitialHeapSize; } - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); // adjust max heap size if necessary if (NewSize + OldSize > MaxHeapSize) { - if (FLAG_IS_CMDLINE(MaxHeapSize)) { + if (_max_heap_size_cmdline) { // somebody set a maximum heap size with the intention that we should not // exceed it. Adjust New/OldSize as necessary. uintx calculated_size = NewSize + OldSize; double shrink_factor = (double) MaxHeapSize / calculated_size; - // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); - // OldSize is already aligned because above we aligned MaxHeapSize to - // _max_alignment, and we just made sure that NewSize is aligned to - // _min_alignment. In initialize_flags() we verified that _max_alignment - // is a multiple of _min_alignment. - OldSize = MaxHeapSize - NewSize; - } else { - MaxHeapSize = NewSize + OldSize; - } - } - // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); + uintx smallerNewSize = align_size_down((uintx)(NewSize * shrink_factor), _gen_alignment); + FLAG_SET_ERGO(uintx, NewSize, MAX2(young_gen_size_lower_bound(), smallerNewSize)); + _initial_gen0_size = NewSize; - // adjust max heap size if necessary - if (NewSize + OldSize > MaxHeapSize) { - if (FLAG_IS_CMDLINE(MaxHeapSize)) { - // somebody set a maximum heap size with the intention that we should not - // exceed it. Adjust New/OldSize as necessary. - uintx calculated_size = NewSize + OldSize; - double shrink_factor = (double) MaxHeapSize / calculated_size; - // align - NewSize = align_size_down((uintx) (NewSize * shrink_factor), _min_alignment); // OldSize is already aligned because above we aligned MaxHeapSize to - // _max_alignment, and we just made sure that NewSize is aligned to - // _min_alignment. In initialize_flags() we verified that _max_alignment - // is a multiple of _min_alignment. - OldSize = MaxHeapSize - NewSize; + // _heap_alignment, and we just made sure that NewSize is aligned to + // _gen_alignment. In initialize_flags() we verified that _heap_alignment + // is a multiple of _gen_alignment. + FLAG_SET_ERGO(uintx, OldSize, MaxHeapSize - NewSize); } else { - MaxHeapSize = NewSize + OldSize; + FLAG_SET_ERGO(uintx, MaxHeapSize, align_size_up(NewSize + OldSize, _heap_alignment)); + _max_heap_byte_size = MaxHeapSize; } } - // need to do this again - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); always_do_update_barrier = UseConcMarkSweepGC; - - // Check validity of heap flags - assert(OldSize % _min_alignment == 0, "old space alignment"); - assert(MaxHeapSize % _max_alignment == 0, "maximum heap alignment"); + TwoGenerationCollectorPolicy::assert_flags(); } // Values set on the command line win over any ergonomically @@ -277,7 +414,7 @@ void GenCollectorPolicy::initialize_size_info() { CollectorPolicy::initialize_size_info(); - // _min_alignment is used for alignment within a generation. + // _space_alignment is used for alignment within a generation. // There is additional alignment done down stream for some // collectors that sometimes causes unwanted rounding up of // generations sizes. @@ -285,35 +422,8 @@ // Determine maximum size of gen0 size_t max_new_size = 0; - if (FLAG_IS_CMDLINE(MaxNewSize) || FLAG_IS_ERGO(MaxNewSize)) { - if (MaxNewSize < _min_alignment) { - max_new_size = _min_alignment; - } - if (MaxNewSize >= _max_heap_byte_size) { - max_new_size = align_size_down(_max_heap_byte_size - _min_alignment, - _min_alignment); - warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or " - "greater than the entire heap (" SIZE_FORMAT "k). A " - "new generation size of " SIZE_FORMAT "k will be used.", - MaxNewSize/K, _max_heap_byte_size/K, max_new_size/K); - } else { - max_new_size = align_size_down(MaxNewSize, _min_alignment); - } - - // The case for FLAG_IS_ERGO(MaxNewSize) could be treated - // specially at this point to just use an ergonomically set - // MaxNewSize to set max_new_size. For cases with small - // heaps such a policy often did not work because the MaxNewSize - // was larger than the entire heap. The interpretation given - // to ergonomically set flags is that the flags are set - // by different collectors for their own special needs but - // are not allowed to badly shape the heap. This allows the - // different collectors to decide what's best for themselves - // without having to factor in the overall heap shape. It - // can be the case in the future that the collectors would - // only make "wise" ergonomics choices and this policy could - // just accept those choices. The choices currently made are - // not always "wise". + if (!FLAG_IS_DEFAULT(MaxNewSize)) { + max_new_size = MaxNewSize; } else { max_new_size = scale_by_NewRatio_aligned(_max_heap_byte_size); // Bound the maximum size by NewSize below (since it historically @@ -382,11 +492,22 @@ _min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size); } + // Write back to flags if necessary + if (NewSize != _initial_gen0_size) { + FLAG_SET_ERGO(uintx, NewSize, _initial_gen0_size); + } + + if (MaxNewSize != _max_gen0_size) { + FLAG_SET_ERGO(uintx, MaxNewSize, _max_gen0_size); + } + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("1: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, _min_gen0_size, _initial_gen0_size, _max_gen0_size); } + + GenCollectorPolicy::assert_size_info(); } // Call this method during the sizing of the gen1 to make @@ -404,14 +525,15 @@ bool result = false; if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { + uintx smallestNewSize = young_gen_size_lower_bound(); if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && - (heap_size >= min_gen1_size + _min_alignment)) { + (heap_size >= min_gen1_size + smallestNewSize)) { // Adjust gen0 down to accommodate min_gen1_size - *gen0_size_ptr = align_size_down_bounded(heap_size - min_gen1_size, _min_alignment); + *gen0_size_ptr = align_size_down_bounded(heap_size - min_gen1_size, _gen_alignment); assert(*gen0_size_ptr > 0, "Min gen0 is too large"); result = true; } else { - *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _min_alignment); + *gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _gen_alignment); } } return result; @@ -432,36 +554,31 @@ // The maximum gen1 size can be determined from the maximum gen0 // and maximum heap size since no explicit flags exits // for setting the gen1 maximum. - _max_gen1_size = _max_heap_byte_size - _max_gen0_size; - _max_gen1_size = - MAX2((uintx)align_size_down(_max_gen1_size, _min_alignment), _min_alignment); + _max_gen1_size = MAX2(_max_heap_byte_size - _max_gen0_size, _gen_alignment); + // If no explicit command line flag has been set for the // gen1 size, use what is left for gen1. - if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) { - // The user has not specified any value or ergonomics - // has chosen a value (which may or may not be consistent + if (!FLAG_IS_CMDLINE(OldSize)) { + // The user has not specified any value but the ergonomics + // may have chosen a value (which may or may not be consistent // with the overall heap size). In either case make // the minimum, maximum and initial sizes consistent // with the gen0 sizes and the overall heap sizes. - assert(_min_heap_byte_size > _min_gen0_size, - "gen0 has an unexpected minimum size"); - _min_gen1_size = _min_heap_byte_size - _min_gen0_size; - _min_gen1_size = - MAX2((uintx)align_size_down(_min_gen1_size, _min_alignment), _min_alignment); - _initial_gen1_size = _initial_heap_byte_size - _initial_gen0_size; - _initial_gen1_size = - MAX2((uintx)align_size_down(_initial_gen1_size, _min_alignment), _min_alignment); + _min_gen1_size = MAX2(_min_heap_byte_size - _min_gen0_size, _gen_alignment); + _initial_gen1_size = MAX2(_initial_heap_byte_size - _initial_gen0_size, _gen_alignment); + // _max_gen1_size has already been made consistent above + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); } else { // It's been explicitly set on the command line. Use the // OldSize and then determine the consequences. - _min_gen1_size = OldSize; + _min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size); _initial_gen1_size = OldSize; // If the user has explicitly set an OldSize that is inconsistent // with other command line flags, issue a warning. // The generation minimums and the overall heap mimimum should - // be within one heap alignment. - if ((_min_gen1_size + _min_gen0_size + _min_alignment) < _min_heap_byte_size) { + // be within one generation alignment. + if ((_min_gen1_size + _min_gen0_size + _gen_alignment) < _min_heap_byte_size) { warning("Inconsistency between minimum heap size and minimum " "generation sizes: using minimum heap = " SIZE_FORMAT, _min_heap_byte_size); @@ -475,7 +592,7 @@ // If there is an inconsistency between the OldSize and the minimum and/or // initial size of gen0, since OldSize was explicitly set, OldSize wins. if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, - _min_heap_byte_size, OldSize)) { + _min_heap_byte_size, _min_gen1_size)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, @@ -484,7 +601,7 @@ } // Initial size if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size, - _initial_heap_byte_size, OldSize)) { + _initial_heap_byte_size, _initial_gen1_size)) { if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 " SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT, @@ -499,11 +616,26 @@ _initial_gen1_size = MAX2(_initial_gen1_size, _min_gen1_size); _initial_gen1_size = MIN2(_initial_gen1_size, _max_gen1_size); + // Write back to flags if necessary + if (NewSize != _initial_gen0_size) { + FLAG_SET_ERGO(uintx, NewSize, _max_gen0_size); + } + + if (MaxNewSize != _max_gen0_size) { + FLAG_SET_ERGO(uintx, MaxNewSize, _max_gen0_size); + } + + if (OldSize != _initial_gen1_size) { + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); + } + if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT " Initial gen1 " SIZE_FORMAT " Maximum gen1 " SIZE_FORMAT, _min_gen1_size, _initial_gen1_size, _max_gen1_size); } + + TwoGenerationCollectorPolicy::assert_size_info(); } HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, @@ -826,10 +958,6 @@ // MarkSweepPolicy methods // -MarkSweepPolicy::MarkSweepPolicy() { - initialize_all(); -} - void MarkSweepPolicy::initialize_generations() { _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, 0, AllocFailStrategy::RETURN_NULL); if (_generations == NULL) { --- old/src/share/vm/memory/collectorPolicy.hpp 2013-10-25 15:32:44.000000000 +0200 +++ new/src/share/vm/memory/collectorPolicy.hpp 2013-10-25 15:32:44.000000000 +0200 @@ -61,17 +61,23 @@ protected: GCPolicyCounters* _gc_policy_counters; - // Requires that the concrete subclass sets the alignment constraints - // before calling. + virtual void initialize_alignments(); virtual void initialize_flags(); virtual void initialize_size_info(); + virtual void assert_flags(); + virtual void assert_size_info(); + size_t _initial_heap_byte_size; size_t _max_heap_byte_size; size_t _min_heap_byte_size; - size_t _min_alignment; - size_t _max_alignment; + size_t _space_alignment; + size_t _heap_alignment; + + // Needed to keep information if MaxHeapSize was set on the command line + // when the flag value is aligned etc by ergonomics + bool _max_heap_size_cmdline; // The sizing of the heap are controlled by a sizing policy. AdaptiveSizePolicy* _size_policy; @@ -87,23 +93,20 @@ // mem_allocate() where it returns op.result() bool _all_soft_refs_clear; - CollectorPolicy() : - _min_alignment(1), - _max_alignment(1), - _initial_heap_byte_size(0), - _max_heap_byte_size(0), - _min_heap_byte_size(0), - _size_policy(NULL), - _should_clear_all_soft_refs(false), - _all_soft_refs_clear(false) - {} + CollectorPolicy(); public: + virtual void initialize_all() { + initialize_alignments(); + initialize_flags(); + initialize_size_info(); + } + // Return maximum heap alignment that may be imposed by the policy - static size_t compute_max_alignment(); + static size_t compute_heap_alignment(); - size_t min_alignment() { return _min_alignment; } - size_t max_alignment() { return _max_alignment; } + size_t space_alignment() { return _space_alignment; } + size_t heap_alignment() { return _heap_alignment; } size_t initial_heap_byte_size() { return _initial_heap_byte_size; } size_t max_heap_byte_size() { return _max_heap_byte_size; } @@ -195,6 +198,9 @@ return false; } + // Do any updates required to global flags that are due to heap initialization + // changes + virtual void post_heap_initialize() = 0; }; class ClearedAllSoftRefs : public StackObj { @@ -219,6 +225,10 @@ size_t _initial_gen0_size; size_t _max_gen0_size; + // _gen_alignment and _space_alignment will have the same value most of the + // time. When using large pages they can differ. + size_t _gen_alignment; + GenerationSpec **_generations; // Return true if an allocation should be attempted in the older @@ -226,26 +236,36 @@ // false, otherwise. virtual bool should_try_older_generation_allocation(size_t word_size) const; + void initialize_alignments(); void initialize_flags(); void initialize_size_info(); + void assert_flags(); + void assert_size_info(); + // Try to allocate space by expanding the heap. virtual HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - // Scale the base_size by NewRation according to + // Compute max heap alignment + size_t compute_max_alignment(); + + // Scale the base_size by NewRatio according to // result = base_size / (NewRatio + 1) // and align by min_alignment() size_t scale_by_NewRatio_aligned(size_t base_size); - // Bound the value by the given maximum minus the - // min_alignment. + // Bound the value by the given maximum minus the min_alignment size_t bound_minus_alignment(size_t desired_size, size_t maximum_size); public: + GenCollectorPolicy() : CollectorPolicy(), _min_gen0_size(0), _initial_gen0_size(0), + _max_gen0_size(0), _generations(NULL) {} + // Accessors size_t min_gen0_size() { return _min_gen0_size; } size_t initial_gen0_size() { return _initial_gen0_size; } size_t max_gen0_size() { return _max_gen0_size; } + size_t gen_alignment() { return _gen_alignment; } virtual int number_of_generations() = 0; @@ -256,14 +276,15 @@ virtual GenCollectorPolicy* as_generation_policy() { return this; } - virtual void initialize_generations() = 0; + virtual void initialize_generations() { }; virtual void initialize_all() { - initialize_flags(); - initialize_size_info(); + CollectorPolicy::initialize_all(); initialize_generations(); } + size_t young_gen_size_lower_bound(); + HeapWord* mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded); @@ -275,9 +296,12 @@ size_t init_promo_size, size_t init_survivor_size); - // The alignment used for eden and survivors within the young gen - // and for boundary between young gen and old gen. - static size_t intra_heap_alignment() { + virtual void post_heap_initialize() { + assert(_max_gen0_size == MaxNewSize, "Should be taken care of by initialize_size_info"); + } + + // The alignment used for boundary between young gen and old gen + static size_t default_gen_alignment() { return 64 * K * HeapWordSize; } }; @@ -296,9 +320,14 @@ void initialize_flags(); void initialize_size_info(); - void initialize_generations() { ShouldNotReachHere(); } + + void assert_flags(); + void assert_size_info(); public: + TwoGenerationCollectorPolicy() : GenCollectorPolicy(), _min_gen1_size(0), + _initial_gen1_size(0), _max_gen1_size(0) {} + // Accessors size_t min_gen1_size() { return _min_gen1_size; } size_t initial_gen1_size() { return _initial_gen1_size; } @@ -324,7 +353,7 @@ void initialize_generations(); public: - MarkSweepPolicy(); + MarkSweepPolicy() {} MarkSweepPolicy* as_mark_sweep_policy() { return this; } --- old/src/share/vm/memory/defNewGeneration.cpp 2013-10-25 15:32:44.000000000 +0200 +++ new/src/share/vm/memory/defNewGeneration.cpp 2013-10-25 15:32:44.000000000 +0200 @@ -204,7 +204,7 @@ // Compute the maximum eden and survivor space sizes. These sizes // are computed assuming the entire reserved space is committed. // These values are exported as performance counters. - uintx alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment(); + uintx alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, alignment); _max_eden_size = size - (2*_max_survivor_size); @@ -235,7 +235,7 @@ bool clear_space, bool mangle_space) { uintx alignment = - GenCollectedHeap::heap()->collector_policy()->min_alignment(); + GenCollectedHeap::heap()->collector_policy()->space_alignment(); // If the spaces are being cleared (only done at heap initialization // currently), the survivor spaces need not be empty. @@ -473,7 +473,7 @@ } size_t DefNewGeneration::max_capacity() const { - const size_t alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment(); + const size_t alignment = GenCollectedHeap::heap()->collector_policy()->space_alignment(); const size_t reserved_bytes = reserved().byte_size(); return reserved_bytes - compute_survivor_size(reserved_bytes, alignment); } --- old/src/share/vm/memory/genCollectedHeap.cpp 2013-10-25 15:32:45.000000000 +0200 +++ new/src/share/vm/memory/genCollectedHeap.cpp 2013-10-25 15:32:45.000000000 +0200 @@ -111,7 +111,7 @@ int n_covered_regions = 0; ReservedSpace heap_rs; - size_t heap_alignment = collector_policy()->max_alignment(); + size_t heap_alignment = collector_policy()->heap_alignment(); heap_address = allocate(heap_alignment, &total_reserved, &n_covered_regions, &heap_rs); --- old/src/share/vm/memory/sharedHeap.cpp 2013-10-25 15:32:46.000000000 +0200 +++ new/src/share/vm/memory/sharedHeap.cpp 2013-10-25 15:32:45.000000000 +0200 @@ -247,6 +247,7 @@ } void SharedHeap::post_initialize() { + CollectedHeap::post_initialize(); ref_processing_init(); } --- old/src/share/vm/memory/universe.cpp 2013-10-25 15:32:46.000000000 +0200 +++ new/src/share/vm/memory/universe.cpp 2013-10-25 15:32:46.000000000 +0200 @@ -765,6 +765,7 @@ } else if (UseG1GC) { #if INCLUDE_ALL_GCS G1CollectorPolicy* g1p = new G1CollectorPolicy(); + g1p->initialize_all(); G1CollectedHeap* g1h = new G1CollectedHeap(g1p); Universe::_collectedHeap = g1h; #else // INCLUDE_ALL_GCS @@ -789,6 +790,7 @@ } else { // default old generation gc_policy = new MarkSweepPolicy(); } + gc_policy->initialize_all(); Universe::_collectedHeap = new GenCollectedHeap(gc_policy); } --- old/src/share/vm/prims/whitebox.cpp 2013-10-25 15:32:47.000000000 +0200 +++ new/src/share/vm/prims/whitebox.cpp 2013-10-25 15:32:47.000000000 +0200 @@ -105,7 +105,7 @@ gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap " SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT, p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(), - p->min_alignment(), p->max_alignment()); + p->space_alignment(), p->heap_alignment()); } WB_END --- old/src/share/vm/runtime/arguments.cpp 2013-10-25 15:32:47.000000000 +0200 +++ new/src/share/vm/runtime/arguments.cpp 2013-10-25 15:32:47.000000000 +0200 @@ -1505,7 +1505,7 @@ } #endif // INCLUDE_ALL_GCS _conservative_max_heap_alignment = MAX3(heap_alignment, os::max_page_size(), - CollectorPolicy::compute_max_alignment()); + CollectorPolicy::compute_heap_alignment()); } void Arguments::set_ergonomics_flags() { @@ -2162,6 +2162,10 @@ #if INCLUDE_ALL_GCS if (UseG1GC) { + status = status && verify_percentage(G1NewSizePercent, "G1NewSizePercent"); + status = status && verify_percentage(G1MaxNewSizePercent, "G1MaxNewSizePercent"); + status = status && verify_interval(G1NewSizePercent, 0, G1MaxNewSizePercent, "G1NewSizePercent"); + status = status && verify_percentage(InitiatingHeapOccupancyPercent, "InitiatingHeapOccupancyPercent"); status = status && verify_min_value(G1RefProcDrainInterval, 1, --- old/test/gc/arguments/TestMaxHeapSizeTools.java 2013-10-25 15:32:48.000000000 +0200 +++ new/test/gc/arguments/TestMaxHeapSizeTools.java 2013-10-25 15:32:48.000000000 +0200 @@ -64,32 +64,29 @@ long newPlusOldSize = values[0] + values[1]; long smallValue = newPlusOldSize / 2; long largeValue = newPlusOldSize * 2; + long maxHeapSize = largeValue + (2 * 1024 * 1024); // -Xms is not set - checkErgonomics(new String[] { gcflag, "-Xmx16M" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-XX:InitialHeapSize=0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=0" }, values, -1, -1); // -Xms is set to zero - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1); // -Xms is set to small value - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1); // -Xms is set to large value - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue }, values, largeValue, largeValue); - // the next case has already been checked elsewhere and gives an error - // checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - // the next case has already been checked elsewhere too - // checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, values[0], largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx16M", "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue }, values, largeValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1); } private static long align_up(long value, long alignment) { --- /dev/null 2013-10-25 15:32:48.000000000 +0200 +++ new/test/gc/arguments/TestMaxNewSize.java 2013-10-25 15:32:48.000000000 +0200 @@ -0,0 +1,124 @@ +/* +* 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 TestMaxNewSize + * @key gc + * @bug 7057939 + * @summary Make sure that MaxNewSize always has a useful value after argument + * processing. + * @library /testlibrary + * @build TestMaxNewSize + * @run main TestMaxNewSize -XX:+UseSerialGC + * @run main TestMaxNewSize -XX:+UseParallelGC + * @run main TestMaxNewSize -XX:+UseConcMarkSweepGC + * @run main TestMaxNewSize -XX:+UseG1GC + * @author thomas.schatzl@oracle.com, jesper.wilhelmsson@oracle.com + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.math.BigInteger; + +import java.util.ArrayList; +import java.util.Arrays; + +import com.oracle.java.testlibrary.*; + +public class TestMaxNewSize { + + private static void checkMaxNewSize(String[] flags, int heapsize) throws Exception { + BigInteger actual = new BigInteger(getMaxNewSize(flags)); + System.out.println(actual); + if (actual.compareTo(new BigInteger((new Long(heapsize)).toString())) == 1) { + throw new RuntimeException("MaxNewSize value set to \"" + actual + + "\", expected otherwise when running with the following flags: " + Arrays.asList(flags).toString()); + } + } + + private static void checkIncompatibleNewSize(String[] flags) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(flags)); + finalargs.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Initial young gen size set larger than the maximum young gen size"); + } + + private static boolean isRunningG1(String[] args) { + for (int i = 0; i < args.length; i++) { + if (args[i].contains("+UseG1GC")) { + return true; + } + } + return false; + } + + private static String getMaxNewSize(String[] flags) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(flags)); + if (isRunningG1(flags)) { + finalargs.add("-XX:G1HeapRegionSize=1M"); + } + finalargs.add("-XX:+PrintFlagsFinal"); + finalargs.add("-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + String stdout = output.getStdout(); + //System.out.println(stdout); + return getFlagValue("MaxNewSize", stdout); + } + + private static String getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return match.substring(match.lastIndexOf(" ") + 1, match.length()); + } + + public static void main(String args[]) throws Exception { + String gcName = args[0]; + final int M32 = 32 * 1024 * 1024; + final int M64 = 64 * 1024 * 1024; + final int M96 = 96 * 1024 * 1024; + final int M128 = 128 * 1024 * 1024; + checkMaxNewSize(new String[] { gcName, "-Xmx128M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewRatio=5" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewSize=32M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:OldSize=96M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewSize=32M", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-XX:NewRatio=6", "-XX:MaxNewSize=32M" }, M32); + checkMaxNewSize(new String[] { gcName, "-Xmx128M", "-Xms96M" }, M128); + checkMaxNewSize(new String[] { gcName, "-Xmx96M", "-Xms96M" }, M96); + checkIncompatibleNewSize(new String[] {gcName, "-XX:NewSize=100M", "-XX:MaxNewSize=50M"}); + // User input should be checked before any alignment adjusts the values + checkIncompatibleNewSize(new String[] {gcName, "-XX:NewSize=" + M32, "-XX:MaxNewSize=" + (M32 - 1)}); + } +}