changeset 13060:8f07aa079343

8016309: assert(eden_size > 0 && survivor_size > 0) failed: just checking 7057939: jmap shows MaxNewSize=4GB when Java is using parallel collector Summary: Major cleanup of the collectorpolicy classes Reviewed-by: tschatzl, jcoomes
author jwilhelm
date Fri, 01 Nov 2013 17:09:38 +0100
parents 46d7652b223c
children 610be0309a79
files src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp src/share/vm/gc_implementation/g1/heapRegion.cpp src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp src/share/vm/gc_interface/collectedHeap.cpp src/share/vm/memory/collectorPolicy.cpp src/share/vm/memory/collectorPolicy.hpp src/share/vm/memory/defNewGeneration.cpp src/share/vm/memory/genCollectedHeap.cpp src/share/vm/memory/sharedHeap.cpp src/share/vm/memory/universe.cpp src/share/vm/prims/whitebox.cpp src/share/vm/runtime/arguments.cpp test/gc/arguments/TestMaxHeapSizeTools.java test/gc/arguments/TestMaxNewSize.java
diffstat 28 files changed, 725 insertions(+), 435 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -47,8 +47,9 @@
 // ConcurrentMarkSweepPolicy methods
 //
 
-ConcurrentMarkSweepPolicy::ConcurrentMarkSweepPolicy() {
-  initialize_all();
+void ConcurrentMarkSweepPolicy::initialize_alignments() {
+  _space_alignment = _gen_alignment = (uintx)Generation::GenGrain;
+  _heap_alignment = compute_heap_alignment();
 }
 
 void ConcurrentMarkSweepPolicy::initialize_generations() {
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -29,10 +29,11 @@
 
 class ConcurrentMarkSweepPolicy : public TwoGenerationCollectorPolicy {
  protected:
+  void initialize_alignments();
   void initialize_generations();
 
  public:
-  ConcurrentMarkSweepPolicy();
+  ConcurrentMarkSweepPolicy() {}
 
   ConcurrentMarkSweepPolicy* as_concurrent_mark_sweep_policy() { return this; }
 
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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");
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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_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();
+  _heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size);
 }
 
 void G1CollectorPolicy::initialize_flags() {
-  _min_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);
+  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");
@@ -344,8 +355,13 @@
     }
   }
 
-  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");
+  if (NewSize > MaxNewSize) {
+    if (FLAG_IS_CMDLINE(MaxNewSize)) {
+      warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
+              "A new max generation size of " SIZE_FORMAT "k will be used.",
+              NewSize/K, MaxNewSize/K, NewSize/K);
+    }
+    MaxNewSize = NewSize;
   }
 
   if (FLAG_IS_CMDLINE(NewSize)) {
@@ -378,34 +394,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() {
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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...
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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);
 
--- a/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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 &&
--- a/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/adjoiningGenerations.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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; }
--- a/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/asPSOldGen.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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();
--- a/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/asPSYoungGen.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/parallelScavenge/generationSizer.hpp"
+#include "memory/collectorPolicy.hpp"
+
+void GenerationSizer::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 GenerationSizer::initialize_alignments() {
+  _space_alignment = _gen_alignment = default_gen_alignment();
+  _heap_alignment = compute_heap_alignment();
+}
+
+void GenerationSizer::initialize_flags() {
+  // Do basic sizing work
+  TwoGenerationCollectorPolicy::initialize_flags();
+
+  assert(UseSerialGC ||
+          !FLAG_IS_DEFAULT(ParallelGCThreads) ||
+          (ParallelGCThreads > 0),
+         "ParallelGCThreads should be set before flag initialization");
+
+  // The survivor ratio's are calculated "raw", unlike the
+  // default gc, which adds 2 to the ratio value. We need to
+  // make sure the values are valid before using them.
+  if (MinSurvivorRatio < 3) {
+    FLAG_SET_ERGO(uintx, MinSurvivorRatio, 3);
+  }
+
+  if (InitialSurvivorRatio < 3) {
+    FLAG_SET_ERGO(uintx, InitialSurvivorRatio, 3);
+  }
+}
+
+void GenerationSizer::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");
+}
--- a/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -31,41 +31,17 @@
 // TwoGenerationCollectorPolicy. Lets reuse it!
 
 class GenerationSizer : public TwoGenerationCollectorPolicy {
- public:
-  GenerationSizer() {
-    // Partial init only!
-    initialize_flags();
-    initialize_size_info();
-  }
+ private:
 
-  void initialize_flags() {
-    // Do basic sizing work
-    TwoGenerationCollectorPolicy::initialize_flags();
+  void trace_gen_sizes(const char* const str);
 
-    assert(UseSerialGC ||
-           !FLAG_IS_DEFAULT(ParallelGCThreads) ||
-           (ParallelGCThreads > 0),
-           "ParallelGCThreads should be set before flag initialization");
+  // The alignment used for boundary between young gen and old gen
+  static size_t default_gen_alignment() { return 64 * K * HeapWordSize; }
 
-    // The survivor ratio's are calculated "raw", unlike the
-    // 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;
-    }
+ protected:
 
-    if (InitialSurvivorRatio < 3) {
-      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_alignments();
+  void initialize_flags();
+  void initialize_size_info();
 };
-
 #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_GENERATIONSIZER_HPP
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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();
-
-  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);
+  _collector_policy->initialize_all();
 
-  // 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);
+  const size_t heap_size = _collector_policy->max_heap_byte_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);
-
+  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
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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 the various areas
+  size_t space_alignment()      { return _collector_policy->space_alignment(); }
+  size_t generation_alignment() { return _collector_policy->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(); }
+  // 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
--- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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
--- a/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/psAdaptiveSizePolicy.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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;
   }
 
--- a/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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()) {
--- a/src/share/vm/gc_interface/collectedHeap.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/gc_interface/collectedHeap.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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;
--- a/src/share/vm/memory/collectorPolicy.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/collectorPolicy.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -47,54 +47,107 @@
 
 // CollectorPolicy methods.
 
+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)
+{}
+
+#ifdef ASSERT
+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");
+}
+#endif // ASSERT
+
 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));
+  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 (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("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;
   }
 
-  MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, _min_alignment);
+  // Check heap parameter properties
+  if (InitialHeapSize < M) {
+    vm_exit_during_initialization("Too small initial heap");
+  }
+  if (_min_heap_byte_size < M) {
+    vm_exit_during_initialization("Too small minimum heap");
+  }
+
+  // User inputs from -Xmx and -Xms must be aligned
+  _min_heap_byte_size = align_size_up(_min_heap_byte_size, _heap_alignment);
+  uintx aligned_initial_heap_size = align_size_up(InitialHeapSize, _heap_alignment);
+  uintx aligned_max_heap_size = align_size_up(MaxHeapSize, _heap_alignment);
+
+  // Write back to flags if the values changed
+  if (aligned_initial_heap_size != InitialHeapSize) {
+    FLAG_SET_ERGO(uintx, InitialHeapSize, aligned_initial_heap_size);
+  }
+  if (aligned_max_heap_size != MaxHeapSize) {
+    FLAG_SET_ERGO(uintx, MaxHeapSize, aligned_max_heap_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 (!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));
+
+  DEBUG_ONLY(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);
-
-  // Check heap parameter properties
-  if (_initial_heap_byte_size < 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");
-  }
-  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);
   }
+
+  DEBUG_ONLY(CollectorPolicy::assert_size_info();)
 }
 
 bool CollectorPolicy::use_should_clear_all_soft_refs(bool v) {
@@ -118,7 +171,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
@@ -145,14 +198,21 @@
 
 // GenCollectorPolicy methods.
 
+GenCollectorPolicy::GenCollectorPolicy() :
+    _min_gen0_size(0),
+    _initial_gen0_size(0),
+    _max_gen0_size(0),
+    _gen_alignment(0),
+    _generations(NULL)
+{}
+
 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 +228,181 @@
                                         GCTimeRatio);
 }
 
+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);
+}
+
+#ifdef ASSERT
+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");
+}
+#endif // ASSERT
+
 void GenCollectorPolicy::initialize_flags() {
-  // All sizes must be multiples of the generation granularity.
-  _min_alignment = (uintx) Generation::GenGrain;
-  _max_alignment = compute_max_alignment();
-
   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));
+  assert(_heap_alignment % _gen_alignment == 0,
+         err_msg("heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT,
+                 _heap_alignment, _gen_alignment));
+
+  // All generational heaps have a youngest gen; handle those flags here
 
-  // Adjust max size parameters
-  if (NewSize > MaxNewSize) {
-    MaxNewSize = NewSize;
+  // Make sure the heap is large enough for two generations
+  uintx smallest_new_size = young_gen_size_lower_bound();
+  uintx smallest_heap_size = align_size_up(smallest_new_size + align_size_up(_space_alignment, _gen_alignment),
+                                           _heap_alignment);
+  if (MaxHeapSize < smallest_heap_size) {
+    FLAG_SET_ERGO(uintx, MaxHeapSize, smallest_heap_size);
+    _max_heap_byte_size = MaxHeapSize;
+  }
+  // If needed, synchronize _min_heap_byte size and _initial_heap_byte_size
+  if (_min_heap_byte_size < smallest_heap_size) {
+    _min_heap_byte_size = smallest_heap_size;
+    if (InitialHeapSize < _min_heap_byte_size) {
+      FLAG_SET_ERGO(uintx, InitialHeapSize, smallest_heap_size);
+      _initial_heap_byte_size = smallest_heap_size;
+    }
+  }
+
+  // Now take the actual NewSize into account. We will silently increase NewSize
+  // if the user specified a smaller value.
+  smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment));
+  if (smallest_new_size != NewSize) {
+    FLAG_SET_ERGO(uintx, NewSize, smallest_new_size);
   }
-  NewSize = align_size_down(NewSize, _min_alignment);
-  MaxNewSize = align_size_down(MaxNewSize, _min_alignment);
+  _initial_gen0_size = NewSize;
+
+  if (!FLAG_IS_DEFAULT(MaxNewSize)) {
+    uintx min_new_size = MAX2(_gen_alignment, _min_gen0_size);
 
-  // Check validity of heap flags
-  assert(NewSize     % _min_alignment == 0, "eden space alignment");
-  assert(MaxNewSize  % _min_alignment == 0, "survivor space alignment");
+    if (MaxNewSize >= MaxHeapSize) {
+      // Make sure there is room for an old generation
+      uintx smaller_max_new_size = 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, smaller_max_new_size/K);
+      }
+      FLAG_SET_ERGO(uintx, MaxNewSize, smaller_max_new_size);
+      if (NewSize > MaxNewSize) {
+        FLAG_SET_ERGO(uintx, NewSize, MaxNewSize);
+        _initial_gen0_size = NewSize;
+      }
+    } else if (MaxNewSize < min_new_size) {
+      FLAG_SET_ERGO(uintx, MaxNewSize, min_new_size);
+    } else if (!is_size_aligned(MaxNewSize, _gen_alignment)) {
+      FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _gen_alignment));
+    }
+    _max_gen0_size = MaxNewSize;
+  }
 
-  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 and/or
+    // a small (but not too small) MaxNewSize.
+    if (FLAG_IS_CMDLINE(MaxNewSize)) {
+      warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
+              "A new max generation size of " SIZE_FORMAT "k will be used.",
+              NewSize/K, MaxNewSize/K, NewSize/K);
+    }
+    FLAG_SET_ERGO(uintx, MaxNewSize, NewSize);
+    _max_gen0_size = MaxNewSize;
   }
 
   if (SurvivorRatio < 1 || NewRatio < 1) {
     vm_exit_during_initialization("Invalid young gen ratio specified");
   }
+
+  DEBUG_ONLY(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);
+      uintx smaller_new_size = align_size_down((uintx)(NewSize * shrink_factor), _gen_alignment);
+      FLAG_SET_ERGO(uintx, NewSize, MAX2(young_gen_size_lower_bound(), smaller_new_size));
+      _initial_gen0_size = NewSize;
+
       // 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);
-
-  // 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;
-    } else {
-      MaxHeapSize = NewSize + OldSize;
-    }
-  }
-  // 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");
+  DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_flags();)
 }
 
 // Values set on the command line win over any ergonomically
@@ -277,7 +417,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 +425,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 +495,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);
   }
+
+  DEBUG_ONLY(GenCollectorPolicy::assert_size_info();)
 }
 
 // Call this method during the sizing of the gen1 to make
@@ -404,14 +528,15 @@
   bool result = false;
 
   if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) {
+    uintx smallest_new_size = 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 + smallest_new_size)) {
       // 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 +557,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 +595,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 +604,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 +619,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);
   }
+
+  DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_size_info();)
 }
 
 HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size,
@@ -826,8 +961,9 @@
 // MarkSweepPolicy methods
 //
 
-MarkSweepPolicy::MarkSweepPolicy() {
-  initialize_all();
+void MarkSweepPolicy::initialize_alignments() {
+  _space_alignment = _gen_alignment = (uintx)Generation::GenGrain;
+  _heap_alignment = compute_heap_alignment();
 }
 
 void MarkSweepPolicy::initialize_generations() {
--- a/src/share/vm/memory/collectorPolicy.hpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/collectorPolicy.hpp	Fri Nov 01 17:09:38 2013 +0100
@@ -61,17 +61,23 @@
  protected:
   GCPolicyCounters* _gc_policy_counters;
 
-  // Requires that the concrete subclass sets the alignment constraints
-  // before calling.
+  virtual void initialize_alignments() = 0;
   virtual void initialize_flags();
   virtual void initialize_size_info();
 
+  DEBUG_ONLY(virtual void assert_flags();)
+  DEBUG_ONLY(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:
-  // Return maximum heap alignment that may be imposed by the policy
-  static size_t compute_max_alignment();
+  virtual void initialize_all() {
+    initialize_alignments();
+    initialize_flags();
+    initialize_size_info();
+  }
 
-  size_t min_alignment()          { return _min_alignment; }
-  size_t max_alignment()          { return _max_alignment; }
+  // Return maximum heap alignment that may be imposed by the policy
+  static size_t compute_heap_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
@@ -229,23 +239,31 @@
   void initialize_flags();
   void initialize_size_info();
 
+  DEBUG_ONLY(void assert_flags();)
+  DEBUG_ONLY(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();
+
   // 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 +274,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,10 +294,8 @@
                                       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() {
-    return 64 * K * HeapWordSize;
+  virtual void post_heap_initialize() {
+    assert(_max_gen0_size == MaxNewSize, "Should be taken care of by initialize_size_info");
   }
 };
 
@@ -296,9 +313,14 @@
 
   void initialize_flags();
   void initialize_size_info();
-  void initialize_generations()                { ShouldNotReachHere(); }
+
+  DEBUG_ONLY(void assert_flags();)
+  DEBUG_ONLY(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; }
@@ -321,10 +343,11 @@
 
 class MarkSweepPolicy : public TwoGenerationCollectorPolicy {
  protected:
+  void initialize_alignments();
   void initialize_generations();
 
  public:
-  MarkSweepPolicy();
+  MarkSweepPolicy() {}
 
   MarkSweepPolicy* as_mark_sweep_policy() { return this; }
 
--- a/src/share/vm/memory/defNewGeneration.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/defNewGeneration.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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);
 }
--- a/src/share/vm/memory/genCollectedHeap.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/genCollectedHeap.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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);
--- a/src/share/vm/memory/sharedHeap.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/sharedHeap.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -247,6 +247,7 @@
 }
 
 void SharedHeap::post_initialize() {
+  CollectedHeap::post_initialize();
   ref_processing_init();
 }
 
--- a/src/share/vm/memory/universe.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/memory/universe.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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);
   }
--- a/src/share/vm/prims/whitebox.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/prims/whitebox.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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
 
--- a/src/share/vm/runtime/arguments.cpp	Mon Oct 21 18:56:20 2013 +0200
+++ b/src/share/vm/runtime/arguments.cpp	Fri Nov 01 17:09:38 2013 +0100
@@ -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() {
@@ -2165,6 +2165,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,
--- a/test/gc/arguments/TestMaxHeapSizeTools.java	Mon Oct 21 18:56:20 2013 +0200
+++ b/test/gc/arguments/TestMaxHeapSizeTools.java	Fri Nov 01 17:09:38 2013 +0100
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/arguments/TestMaxNewSize.java	Fri Nov 01 17:09:38 2013 +0100
@@ -0,0 +1,122 @@
+/*
+* 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<String> finalargs = new ArrayList<String>();
+    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<String> finalargs = new ArrayList<String>();
+    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);
+    checkMaxNewSize(new String[] { gcName, "-XX:NewSize=128M", "-XX:MaxNewSize=50M"}, M128);
+  }
+}