--- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-09-30 21:53:52.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-09-30 21:53:52.000000000 +0200 @@ -2181,10 +2181,6 @@ 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-09-30 21:53:52.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2013-09-30 21:53:52.000000000 +0200 @@ -1092,7 +1092,9 @@ jint initialize(); // Return the (conservative) maximum heap alignment for any G1 heap - static size_t conservative_max_heap_alignment(); + static size_t conservative_max_heap_alignment() { + return HeapRegion::max_region_size(); + } // Initialize weak reference processing. virtual void ref_processing_init(); --- old/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp 2013-09-30 21:53:53.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp 2013-09-30 21:53:53.000000000 +0200 @@ -324,17 +324,26 @@ size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); _max_alignment = MAX3(card_table_alignment, _min_alignment, page_size); + 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(); } -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"); @@ -375,34 +384,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-09-30 21:53:53.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp 2013-09-30 21:53:53.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; @@ -167,11 +175,6 @@ void initialize_flags(); - void initialize_all() { - initialize_flags(); - initialize_size_info(); - } - CollectionSetChooser* _collectionSetChooser; double _full_collection_start_sec; @@ -933,6 +936,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-09-30 21:53:54.000000000 +0200 +++ new/src/share/vm/gc_implementation/g1/heapRegion.cpp 2013-09-30 21:53:54.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-09-30 21:53:54.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp 2013-09-30 21:53:54.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-09-30 21:53:55.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp 2013-09-30 21:53:55.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/generationSizer.hpp 2013-09-30 21:53:55.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp 2013-09-30 21:53:55.000000000 +0200 @@ -31,19 +31,29 @@ // TwoGenerationCollectorPolicy. Lets reuse it! class GenerationSizer : public TwoGenerationCollectorPolicy { - public: +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); + } + } + +public: GenerationSizer() { - // Partial init only! - initialize_flags(); - initialize_size_info(); + initialize_all(); } void initialize_flags() { // Do basic sizing work TwoGenerationCollectorPolicy::initialize_flags(); - // If the user hasn't explicitly set the number of worker - // threads, set the count. assert(UseSerialGC || !FLAG_IS_DEFAULT(ParallelGCThreads) || (ParallelGCThreads > 0), @@ -61,13 +71,30 @@ } } - 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() { + TwoGenerationCollectorPolicy::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"); + _min_alignment = round_to(page_sz, intra_heap_alignment()); + + // Update sizes to reflect the selected page size. + _min_gen0_size = align_size_up(_min_gen0_size, _min_alignment); + _initial_gen0_size = MAX2(align_size_up_(_initial_gen0_size, _min_alignment), _min_gen0_size); + _max_gen0_size = align_size_up(_max_gen0_size, _min_alignment); + + // Align old gen size down to preserve specified heap size. Adjust all other values. + _max_gen1_size = max_heap_byte_size() - _max_gen0_size; + _min_gen1_size = MIN2(align_size_up_(_min_gen1_size, _min_alignment), _max_gen1_size); + _initial_gen1_size = MIN2(align_size_up_(_initial_gen1_size, _min_alignment), _max_gen1_size); + + trace_gen_sizes("ps heap rnd"); + } }; #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GENERATIONSIZER_HPP --- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2013-09-30 21:53:56.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp 2013-09-30 21:53:56.000000000 +0200 @@ -52,76 +52,27 @@ 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); - } -} + size_t ParallelScavengeHeap::intra_heap_alignment() { + return GenCollectorPolicy::intra_heap_alignment(); + } + + size_t ParallelScavengeHeap::alignment() { + return collector_policy()->min_alignment(); + } 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(); - 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->max_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, alignment(), heap_rs.base(), heap_rs.size()); if (!heap_rs.is_reserved()) { @@ -142,12 +93,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 +102,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, alignment()); _old_gen = _gens->old_gen(); _young_gen = _gens->young_gen(); --- old/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2013-09-30 21:53:56.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp 2013-09-30 21:53:56.000000000 +0200 @@ -55,13 +55,11 @@ static ParallelScavengeHeap* _psh; - size_t _young_gen_alignment; - size_t _old_gen_alignment; + // Actual alignment for generation sizes. + size_t 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 +78,12 @@ 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()); + ParallelScavengeHeap() : CollectedHeap(), _death_march_count(0) { } // Return the (conservative) maximum heap alignment static size_t conservative_max_heap_alignment() { - return intra_heap_alignment(); + return GenCollectorPolicy::intra_heap_alignment(); } // For use by VM operations @@ -122,12 +117,12 @@ 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; } + size_t young_gen_alignment() { return alignment(); } + size_t old_gen_alignment() { return alignment(); } // 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() { return 64 * K * HeapWordSize; } + size_t intra_heap_alignment(); size_t capacity() const; size_t used() const; @@ -263,11 +258,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/psYoungGen.cpp 2013-09-30 21:53:57.000000000 +0200 +++ new/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp 2013-09-30 21:53:57.000000000 +0200 @@ -158,6 +158,7 @@ // Compute sizes size_t alignment = heap->intra_heap_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); --- old/src/share/vm/gc_interface/collectedHeap.cpp 2013-09-30 21:53:57.000000000 +0200 +++ new/src/share/vm/gc_interface/collectedHeap.cpp 2013-09-30 21:53:57.000000000 +0200 @@ -475,6 +475,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-09-30 21:53:58.000000000 +0200 +++ new/src/share/vm/memory/collectorPolicy.cpp 2013-09-30 21:53:58.000000000 +0200 @@ -52,6 +52,21 @@ return MAX2(alignment, align_size_down_(size, alignment)); } +void CollectorPolicy::assert_flags() { + assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes"); + assert(InitialHeapSize % _min_alignment == 0, "InitialHeapSize alignment"); + assert(MaxHeapSize % _max_alignment == 0, "MaxHeapSize alignment"); +} + +void CollectorPolicy::assert_size_info() { + 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 % _min_alignment == 0, "min_heap_byte_size alignment"); + assert(_initial_heap_byte_size % _min_alignment == 0, "initial_heap_byte_size alignment"); + assert(_max_heap_byte_size % _max_alignment == 0, "max_heap_byte_size alignment"); +} + void CollectorPolicy::initialize_flags() { assert(_max_alignment >= _min_alignment, err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT, @@ -60,8 +75,40 @@ 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"); + if (FLAG_IS_CMDLINE(MaxHeapSize)) { + if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { + vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified"); + } + if (Arguments::min_heap_size() != 0 && MaxHeapSize < Arguments::min_heap_size()) { + vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); + } + _max_heap_size_cmdline = true; + } + + if (FLAG_IS_CMDLINE(InitialHeapSize) && Arguments::min_heap_size() != 0 && + InitialHeapSize < Arguments::min_heap_size()) { + vm_exit_during_initialization("Incompatible minimum and initial 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 < Arguments::min_heap_size()) { + Arguments::set_min_heap_size(InitialHeapSize); + } + } + + // User inputs from -Xmx and -Xms must be aligned + Arguments::set_min_heap_size(align_size_up(Arguments::min_heap_size(), _min_alignment)); + uintx alignedInitialHeapSize = align_size_up(InitialHeapSize, _min_alignment); + uintx alignedMaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); + + // Write back to flags if the values changed + if (alignedInitialHeapSize != InitialHeapSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, alignedInitialHeapSize); + } + if (alignedMaxHeapSize != MaxHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, alignedMaxHeapSize); } if (!is_size_aligned(MaxMetaspaceSize, _max_alignment)) { @@ -90,13 +137,14 @@ if (MetaspaceSize < 256*K) { vm_exit_during_initialization("Too small initial Metaspace size"); } + + CollectorPolicy::assert_flags(); } 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); + _min_heap_byte_size = Arguments::min_heap_size(); + _initial_heap_byte_size = InitialHeapSize; + _max_heap_byte_size = MaxHeapSize; // Check heap parameter properties if (_initial_heap_byte_size < M) { @@ -106,25 +154,14 @@ 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"); - } - if (_max_heap_byte_size < _min_heap_byte_size) { - vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified"); - } - if (_initial_heap_byte_size < _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 (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) { @@ -177,11 +214,7 @@ // GenCollectorPolicy methods. size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) { - size_t x = base_size / (NewRatio+1); - size_t new_gen_size = x > _min_alignment ? - align_size_down(x, _min_alignment) : - _min_alignment; - return new_gen_size; + return restricted_align_down(base_size / (NewRatio + 1), _min_alignment); } size_t GenCollectorPolicy::bound_minus_alignment(size_t desired_size, @@ -203,6 +236,64 @@ GCTimeRatio); } +size_t GenCollectorPolicy::compute_max_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 + // byte entry and the os page size is 4096, the maximum heap size should + // be 512*4096 = 2MB aligned. + size_t alignment = GenRemSet::max_alignment_constraint(rem_set_name()); + + // Parallel GC does its own alignment of the generations to avoid requiring a + // large page (256M on some platforms) for the permanent generation. The + // other collectors should also be updated to do their own alignment and then + // this use of lcm() should be removed. + if (UseLargePages && !UseParallelGC) { + // in presence of large pages we have to make sure that our + // alignment is large page aware + alignment = lcm(os::large_page_size(), alignment); + } + + assert(alignment >= _min_alignment, "Must be"); + + return 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 % _min_alignment == 0, "NewSize alignment"); + assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % _min_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 % _min_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(_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 % _min_alignment == 0, "_min_gen0_size alignment"); + assert(_initial_gen0_size % _min_alignment == 0, "_initial_gen0_size alignment"); + assert(_max_gen0_size % _min_alignment == 0, "_max_gen0_size alignment"); +} + +void TwoGenerationCollectorPolicy::assert_size_info() { + GenCollectorPolicy::assert_size_info(); + 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 % _min_alignment == 0, "_max_gen1_size alignment"); + assert(_initial_gen1_size % _min_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_flags() { // All sizes must be multiples of the generation granularity. _min_alignment = (uintx) Generation::GenGrain; @@ -210,34 +301,79 @@ CollectorPolicy::initialize_flags(); + // This is the absolute minimum for the young generation. It has to hold two + // survivor areas and the eden. We set it here since it is used repeatedly + // throughout the initialization. However this is not necessarily the final + // value of _min_gen0_size. + _min_gen0_size = 3 * intra_heap_alignment(); + + // Make sure the heap is large enough for two generations. + uintx smallestHeapSize = _min_gen0_size + intra_heap_alignment(); + if (MaxHeapSize < smallestHeapSize) { + FLAG_SET_ERGO(uintx, MaxHeapSize, align_size_up(smallestHeapSize, _max_alignment)); + } + // All generational heaps have a youngest gen; handle those flags here. - // Adjust max size parameters - if (NewSize > MaxNewSize) { - MaxNewSize = NewSize; + if (FLAG_IS_CMDLINE(NewSize) && FLAG_IS_CMDLINE(MaxNewSize) && NewSize > MaxNewSize) { + vm_exit_during_initialization("Incompatible initial and maximum young gen sizes specified"); + } + + if (!FLAG_IS_DEFAULT(MaxNewSize)) { + uintx minNewSize = MAX2(_min_alignment, _min_gen0_size); + + if (MaxNewSize >= MaxHeapSize) { + uintx smallerMaxNewSize = MaxHeapSize - _min_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); + } + } else if (MaxNewSize < minNewSize) { + FLAG_SET_ERGO(uintx, MaxNewSize, minNewSize); + } else if (!is_size_aligned(MaxNewSize, _min_alignment)) { + FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _min_alignment)); + } + } + + // Young space must be aligned and have room for eden + two survivors. + // We will silently increase the NewSize even if the user specified a smaller value. + uintx smallestNewSize = MAX2(align_size_up(_min_gen0_size, _min_alignment), + align_size_down(NewSize, _min_alignment)); + if (smallestNewSize != NewSize) { + FLAG_SET_ERGO(uintx, NewSize, smallestNewSize); } - 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); } + 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, _min_alignment)) { + FLAG_SET_ERGO(uintx, OldSize, align_size_down(OldSize, _min_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. @@ -245,58 +381,32 @@ size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); calculated_heapsize = align_size_up(calculated_heapsize, _max_alignment); - MaxHeapSize = calculated_heapsize; - InitialHeapSize = calculated_heapsize; + FLAG_SET_ERGO(uintx, MaxHeapSize, calculated_heapsize); + FLAG_SET_ERGO(uintx, InitialHeapSize, calculated_heapsize); } - MaxHeapSize = align_size_up(MaxHeapSize, _max_alignment); // 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 + if (_max_heap_size_cmdline) { + // Somebody has 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); + FLAG_SET_ERGO(uintx, NewSize, MAX2(_min_gen0_size, (uintx)align_size_down((uintx)(NewSize * shrink_factor), _min_alignment))); - // 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; + FLAG_SET_ERGO(uintx, OldSize, MaxHeapSize - NewSize); } else { - MaxHeapSize = NewSize + OldSize; + FLAG_SET_ERGO(uintx, MaxHeapSize, align_size_up(NewSize + OldSize, _max_alignment)); } } - // 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 @@ -319,35 +429,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 @@ -416,11 +499,18 @@ _min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size); } + // Write back to flag if necessary + if (MaxNewSize != _min_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 @@ -441,15 +531,11 @@ if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && (heap_size >= min_gen1_size + _min_alignment)) { // Adjust gen0 down to accommodate min_gen1_size - *gen0_size_ptr = heap_size - min_gen1_size; - *gen0_size_ptr = - MAX2((uintx)align_size_down(*gen0_size_ptr, _min_alignment), _min_alignment); + *gen0_size_ptr = restricted_align_down(heap_size - min_gen1_size, _min_alignment); assert(*gen0_size_ptr > 0, "Min gen0 is too large"); result = true; } else { - *gen1_size_ptr = heap_size - *gen0_size_ptr; - *gen1_size_ptr = - MAX2((uintx)align_size_down(*gen1_size_ptr, _min_alignment), _min_alignment); + *gen1_size_ptr = restricted_align_down(heap_size - *gen0_size_ptr, _min_alignment); } } return result; @@ -470,29 +556,24 @@ // The maximum gen1 size can be determined from the maximum gen0 // and maximum heap size since no explicit flags exist // 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, _min_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, _min_alignment); + _initial_gen1_size = MAX2(_initial_heap_byte_size - _initial_gen0_size, _min_alignment); + // _max_gen1_size has already been made consistent above + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); } else { // OldSize has 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 @@ -513,7 +594,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, @@ -522,13 +603,15 @@ } // The same as above for the old gen 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, _min_gen0_size, _initial_gen0_size, _max_gen0_size); } } + // update OldSize + FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size); } _min_gen1_size = MIN2(_min_gen1_size, _max_gen1_size); @@ -542,6 +625,8 @@ 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, --- old/src/share/vm/memory/collectorPolicy.hpp 2013-09-30 21:53:58.000000000 +0200 +++ new/src/share/vm/memory/collectorPolicy.hpp 2013-09-30 21:53:58.000000000 +0200 @@ -66,6 +66,14 @@ virtual void initialize_flags(); virtual void initialize_size_info(); + virtual void assert_flags(); + virtual void assert_size_info(); + + virtual void initialize_all() { + initialize_flags(); + initialize_size_info(); + } + size_t _initial_heap_byte_size; size_t _max_heap_byte_size; size_t _min_heap_byte_size; @@ -73,6 +81,10 @@ size_t _min_alignment; size_t _max_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 is controlled by a sizing policy. AdaptiveSizePolicy* _size_policy; @@ -93,6 +105,7 @@ _initial_heap_byte_size(0), _max_heap_byte_size(0), _min_heap_byte_size(0), + _max_heap_size_cmdline(false), _size_policy(NULL), _should_clear_all_soft_refs(false), _all_soft_refs_clear(false) @@ -196,6 +209,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 { @@ -230,9 +246,15 @@ 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); + // 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() @@ -243,6 +265,9 @@ 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; } @@ -257,11 +282,10 @@ 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(); } @@ -275,6 +299,16 @@ virtual void initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size); + + virtual void post_heap_initialize() { + assert(_max_gen0_size == MaxNewSize, "Wasn't this taken care of earlier?"); + } + + // 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() { + return 64 * K * HeapWordSize; + } }; // All of hotspot's current collectors are subtypes of this @@ -291,9 +325,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; } --- old/src/share/vm/memory/sharedHeap.cpp 2013-09-30 21:53:59.000000000 +0200 +++ new/src/share/vm/memory/sharedHeap.cpp 2013-09-30 21:53:59.000000000 +0200 @@ -247,6 +247,7 @@ } void SharedHeap::post_initialize() { + CollectedHeap::post_initialize(); ref_processing_init(); } --- old/src/share/vm/runtime/arguments.cpp 2013-09-30 21:53:59.000000000 +0200 +++ new/src/share/vm/runtime/arguments.cpp 2013-09-30 21:53:59.000000000 +0200 @@ -1405,7 +1405,7 @@ // NULL page is located before the heap, we pad the NULL page to the conservative // maximum alignment that the GC may ever impose upon the heap. size_t displacement_due_to_null_page = align_size_up_(os::vm_page_size(), - Arguments::conservative_max_heap_alignment()); + _conservative_max_heap_alignment); LP64_ONLY(return OopEncodingHeapMax - displacement_due_to_null_page); NOT_LP64(ShouldNotReachHere(); return 0); @@ -2156,6 +2156,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, @@ -2668,9 +2672,10 @@ describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size); + set_min_heap_size((uintx)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. - set_min_heap_size(InitialHeapSize); + // Can be overridden with -XX:InitialHeapSize. + FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size); // -Xmx } else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) { julong long_max_heap_size = 0; --- old/src/share/vm/runtime/globals.hpp 2013-09-30 21:54:00.000000000 +0200 +++ new/src/share/vm/runtime/globals.hpp 2013-09-30 21:54:00.000000000 +0200 @@ -2994,7 +2994,7 @@ product(uintx, OldSize, ScaleForWordSize(4*M), \ "Initial tenured generation size (in bytes)") \ \ - product(uintx, NewSize, ScaleForWordSize(1*M), \ + product(uintx, NewSize, ScaleForWordSize(2*M), \ "Initial new generation size (in bytes)") \ \ product(uintx, MaxNewSize, max_uintx, \ --- old/test/gc/arguments/TestMaxHeapSizeTools.java 2013-09-30 21:54:01.000000000 +0200 +++ new/test/gc/arguments/TestMaxHeapSizeTools.java 2013-09-30 21:54:00.000000000 +0200 @@ -64,32 +64,33 @@ 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); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-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); + // checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-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, "-XX:InitialHeapSize=" + largeValue }, values, values[0], 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-09-30 21:54:01.000000000 +0200 +++ new/test/gc/arguments/TestMaxNewSize.java 2013-09-30 21:54:01.000000000 +0200 @@ -0,0 +1,100 @@ +/* +* 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 String getMaxNewSize(String[] flags) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(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); + } +}