8211424: Allocation of old generation of java heap on alternate memory devices - Parallel GC
authorsangheki
Fri, 21 Dec 2018 08:23:55 -0800
changeset 53117 37930c6ba6d7
parent 53116 bb03098c4dde
child 53118 93a5f4b4c67d
8211424: Allocation of old generation of java heap on alternate memory devices - Parallel GC 8202286: Allocation of old generation of Java heap on alternate memory devices Summary: Enable an experimental feature in HotSpot JVM to allocate old generation of Parallel GC on an alternative memory device, such as NV-DIMMs. Reviewed-by: sangheki, sjohanss Contributed-by: kishor.kharbas@intel.com
src/hotspot/share/gc/parallel/adjoiningGenerations.cpp
src/hotspot/share/gc/parallel/adjoiningGenerations.hpp
src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.cpp
src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.hpp
src/hotspot/share/gc/parallel/adjoiningVirtualSpaces.hpp
src/hotspot/share/gc/parallel/generationSizer.cpp
src/hotspot/share/gc/parallel/generationSizer.hpp
src/hotspot/share/gc/parallel/heterogeneousGenerationSizer.cpp
src/hotspot/share/gc/parallel/heterogeneousGenerationSizer.hpp
src/hotspot/share/gc/parallel/parallelArguments.cpp
src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp
src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp
src/hotspot/share/gc/parallel/psOldGen.cpp
src/hotspot/share/gc/parallel/psParallelCompact.cpp
src/hotspot/share/prims/whitebox.cpp
test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAt.java
test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAtError.java
test/hotspot/jtreg/gc/nvdimm/TestOldObjectsOnNvdimm.java
test/hotspot/jtreg/gc/nvdimm/TestYoungObjectsOnDram.java
--- a/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "gc/parallel/adjoiningGenerations.hpp"
+#include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp"
 #include "gc/parallel/adjoiningVirtualSpaces.hpp"
 #include "gc/parallel/generationSizer.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
@@ -40,8 +41,8 @@
 AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs,
                                            GenerationSizer* policy,
                                            size_t alignment) :
-  _virtual_spaces(old_young_rs, policy->min_old_size(),
-                  policy->min_young_size(), alignment) {
+  _virtual_spaces(new AdjoiningVirtualSpaces(old_young_rs, policy->min_old_size(),
+                                             policy->min_young_size(), alignment)) {
   size_t init_low_byte_size = policy->initial_old_size();
   size_t min_low_byte_size = policy->min_old_size();
   size_t max_low_byte_size = policy->max_old_size();
@@ -61,21 +62,21 @@
     // generation.
 
     // Does the actual creation of the virtual spaces
-    _virtual_spaces.initialize(max_low_byte_size,
-                               init_low_byte_size,
-                               init_high_byte_size);
+    _virtual_spaces->initialize(max_low_byte_size,
+                                init_low_byte_size,
+                                init_high_byte_size);
 
     // Place the young gen at the high end.  Passes in the virtual space.
-    _young_gen = new ASPSYoungGen(_virtual_spaces.high(),
-                                  _virtual_spaces.high()->committed_size(),
+    _young_gen = new ASPSYoungGen(_virtual_spaces->high(),
+                                  _virtual_spaces->high()->committed_size(),
                                   min_high_byte_size,
-                                  _virtual_spaces.high_byte_size_limit());
+                                  _virtual_spaces->high_byte_size_limit());
 
     // Place the old gen at the low end. Passes in the virtual space.
-    _old_gen = new ASPSOldGen(_virtual_spaces.low(),
-                              _virtual_spaces.low()->committed_size(),
+    _old_gen = new ASPSOldGen(_virtual_spaces->low(),
+                              _virtual_spaces->low()->committed_size(),
                               min_low_byte_size,
-                              _virtual_spaces.low_byte_size_limit(),
+                              _virtual_spaces->low_byte_size_limit(),
                               "old", 1);
 
     young_gen()->initialize_work();
@@ -92,8 +93,9 @@
   } else {
 
     // Layout the reserved space for the generations.
+    // If OldGen is allocated on nv-dimm, we need to split the reservation (this is required for windows).
     ReservedSpace old_rs   =
-      virtual_spaces()->reserved_space().first_part(max_low_byte_size);
+      virtual_spaces()->reserved_space().first_part(max_low_byte_size, policy->is_hetero_heap() /* split */);
     ReservedSpace heap_rs  =
       virtual_spaces()->reserved_space().last_part(max_low_byte_size);
     ReservedSpace young_rs = heap_rs.first_part(max_high_byte_size);
@@ -117,6 +119,8 @@
   }
 }
 
+AdjoiningGenerations::AdjoiningGenerations() { }
+
 size_t AdjoiningGenerations::reserved_byte_size() {
   return virtual_spaces()->reserved_space().size();
 }
@@ -279,3 +283,13 @@
     }
   }
 }
+
+AdjoiningGenerations* AdjoiningGenerations::create_adjoining_generations(ReservedSpace old_young_rs,
+                                                                         GenerationSizer* policy,
+                                                                         size_t alignment) {
+  if (policy->is_hetero_heap() && UseAdaptiveGCBoundary) {
+    return new AdjoiningGenerationsForHeteroHeap(old_young_rs, policy, alignment);
+  } else {
+    return new AdjoiningGenerations(old_young_rs, policy, alignment);
+  }
+}
--- a/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -43,27 +43,29 @@
 class AdjoiningGenerations : public CHeapObj<mtGC> {
   friend class VMStructs;
  private:
-  // The young generation and old generation, respectively
-  PSYoungGen* _young_gen;
-  PSOldGen* _old_gen;
-
-  // The spaces used by the two generations.
-  AdjoiningVirtualSpaces _virtual_spaces;
-
   // Move boundary up to expand old gen.  Checks are made to
   // determine if the move can be done with specified limits.
   void request_old_gen_expansion(size_t desired_change_in_bytes);
   // Move boundary down to expand young gen.
   bool request_young_gen_expansion(size_t desired_change_in_bytes);
 
+ protected:
+   // The young generation and old generation, respectively
+   PSYoungGen* _young_gen;
+   PSOldGen* _old_gen;
+
+   // The spaces used by the two generations.
+   AdjoiningVirtualSpaces* _virtual_spaces;
+
  public:
   AdjoiningGenerations(ReservedSpace rs, GenerationSizer* policy, size_t alignment);
+  AdjoiningGenerations();
 
   // Accessors
   PSYoungGen* young_gen() { return _young_gen; }
   PSOldGen* old_gen() { return _old_gen; }
 
-  AdjoiningVirtualSpaces* virtual_spaces() { return &_virtual_spaces; }
+  AdjoiningVirtualSpaces* virtual_spaces() { return _virtual_spaces; }
 
   // Additional space is needed in the old generation.  Check
   // the available space and attempt to move the boundary if more space
@@ -74,7 +76,9 @@
 
   // Return the total byte size of the reserved space
   // for the adjoining generations.
-  size_t reserved_byte_size();
+  virtual size_t reserved_byte_size();
+
+  // Return new AdjoiningGenerations instance based on collector policy (specifically - whether heap is heterogeneous).
+  static AdjoiningGenerations* create_adjoining_generations(ReservedSpace rs, GenerationSizer* policy, size_t alignment);
 };
-
 #endif // SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2018, 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/parallel/adjoiningGenerationsForHeteroHeap.hpp"
+#include "gc/parallel/adjoiningVirtualSpaces.hpp"
+#include "gc/parallel/generationSizer.hpp"
+#include "gc/parallel/parallelScavengeHeap.hpp"
+#include "gc/parallel/psFileBackedVirtualspace.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/align.hpp"
+#include "utilities/ostream.hpp"
+
+// Create two virtual spaces (HeteroVirtualSpaces), low() on nv-dimm memory, high() on dram.
+// create ASPSOldGen and ASPSYoungGen the same way as in base class
+
+AdjoiningGenerationsForHeteroHeap::AdjoiningGenerationsForHeteroHeap(ReservedSpace old_young_rs, GenerationSizer* policy, size_t alignment) :
+  _total_size_limit(policy->max_heap_byte_size()) {
+  size_t init_old_byte_size = policy->initial_old_size();
+  size_t min_old_byte_size = policy->min_old_size();
+  size_t max_old_byte_size = policy->max_old_size();
+  size_t init_young_byte_size = policy->initial_young_size();
+  size_t min_young_byte_size = policy->min_young_size();
+  size_t max_young_byte_size = policy->max_young_size();
+  // create HeteroVirtualSpaces which is composed of non-overlapping virtual spaces.
+  HeteroVirtualSpaces* hetero_virtual_spaces = new HeteroVirtualSpaces(old_young_rs, min_old_byte_size,
+                                                                       min_young_byte_size, _total_size_limit, alignment);
+
+  assert(min_old_byte_size <= init_old_byte_size &&
+         init_old_byte_size <= max_old_byte_size, "Parameter check");
+  assert(min_young_byte_size <= init_young_byte_size &&
+         init_young_byte_size <= max_young_byte_size, "Parameter check");
+
+  assert(UseAdaptiveGCBoundary, "Should be used only when UseAdaptiveGCBoundary is true");
+
+  // Initialize the virtual spaces. Then pass a virtual space to each generation
+  // for initialization of the generation.
+
+  // Does the actual creation of the virtual spaces
+  hetero_virtual_spaces->initialize(max_old_byte_size, init_old_byte_size, init_young_byte_size);
+
+  _young_gen = new ASPSYoungGen(hetero_virtual_spaces->high(),
+                                hetero_virtual_spaces->high()->committed_size() /* intial_size */,
+                                min_young_byte_size,
+                                hetero_virtual_spaces->max_young_size());
+
+  _old_gen = new ASPSOldGen(hetero_virtual_spaces->low(),
+                            hetero_virtual_spaces->low()->committed_size() /* intial_size */,
+                            min_old_byte_size,
+                            hetero_virtual_spaces->max_old_size(), "old", 1);
+
+  young_gen()->initialize_work();
+  assert(young_gen()->reserved().byte_size() <= young_gen()->gen_size_limit(), "Consistency check");
+  assert(old_young_rs.size() >= young_gen()->gen_size_limit(), "Consistency check");
+
+  old_gen()->initialize_work("old", 1);
+  assert(old_gen()->reserved().byte_size() <= old_gen()->gen_size_limit(), "Consistency check");
+  assert(old_young_rs.size() >= old_gen()->gen_size_limit(), "Consistency check");
+
+  _virtual_spaces = hetero_virtual_spaces;
+}
+
+size_t AdjoiningGenerationsForHeteroHeap::required_reserved_memory(GenerationSizer* policy) {
+  // This is the size that young gen can grow to, when AdaptiveGCBoundary is true.
+  size_t max_yg_size = policy->max_heap_byte_size() - policy->min_old_size();
+  // This is the size that old gen can grow to, when AdaptiveGCBoundary is true.
+  size_t max_old_size = policy->max_heap_byte_size() - policy->min_young_size();
+
+  return max_yg_size + max_old_size;
+}
+
+// We override this function since size of reservedspace here is more than heap size and
+// callers expect this function to return heap size.
+size_t AdjoiningGenerationsForHeteroHeap::reserved_byte_size() {
+  return total_size_limit();
+}
+
+AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::HeteroVirtualSpaces(ReservedSpace rs, size_t min_old_byte_size, size_t min_yg_byte_size, size_t max_total_size, size_t alignment) :
+                                                                            AdjoiningVirtualSpaces(rs, min_old_byte_size, min_yg_byte_size, alignment),
+                                                                            _max_total_size(max_total_size),
+                                                                            _min_old_byte_size(min_old_byte_size), _min_young_byte_size(min_yg_byte_size),
+                                                                            _max_old_byte_size(_max_total_size - _min_young_byte_size),
+                                                                            _max_young_byte_size(_max_total_size - _min_old_byte_size) {
+}
+
+void AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::initialize(size_t initial_old_reserved_size, size_t init_old_byte_size,
+                                                                        size_t init_young_byte_size) {
+
+  // This is the reserved space exclusively for old generation.
+  ReservedSpace low_rs = _reserved_space.first_part(_max_old_byte_size, true);
+  // Intially we only assign 'initial_old_reserved_size' of the reserved space to old virtual space.
+  low_rs = low_rs.first_part(initial_old_reserved_size);
+
+  // This is the reserved space exclusively for young generation.
+  ReservedSpace high_rs = _reserved_space.last_part(_max_old_byte_size).first_part(_max_young_byte_size);
+
+  // Carve out 'initial_young_reserved_size' of reserved space.
+  size_t initial_young_reserved_size = _max_total_size - initial_old_reserved_size;
+  high_rs = high_rs.last_part(_max_young_byte_size - initial_young_reserved_size);
+
+  _low = new PSFileBackedVirtualSpace(low_rs, alignment(), AllocateOldGenAt);
+  if (!static_cast <PSFileBackedVirtualSpace*>(_low)->initialize()) {
+    vm_exit_during_initialization("Could not map space for old generation at given AllocateOldGenAt path");
+  }
+
+  if (!_low->expand_by(init_old_byte_size)) {
+    vm_exit_during_initialization("Could not reserve enough space for object heap");
+  }
+
+  _high = new PSVirtualSpaceHighToLow(high_rs, alignment());
+  if (!_high->expand_by(init_young_byte_size)) {
+    vm_exit_during_initialization("Could not reserve enough space for object heap");
+  }
+}
+
+// Since the virtual spaces are non-overlapping, there is no boundary as such.
+// We replicate the same behavior and maintain the same invariants as base class 'AdjoiningVirtualSpaces' by
+// increasing old generation size and decreasing young generation size by same amount.
+bool AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::adjust_boundary_up(size_t change_in_bytes) {
+  assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
+  DEBUG_ONLY(size_t total_size_before = young_vs()->reserved_size() + old_vs()->reserved_size());
+
+  size_t bytes_needed = change_in_bytes;
+  size_t uncommitted_in_old = MIN2(old_vs()->uncommitted_size(), bytes_needed);
+  bool old_expanded = false;
+
+  // 1. Try to expand old within its reserved space.
+  if (uncommitted_in_old != 0) {
+    if (!old_vs()->expand_by(uncommitted_in_old)) {
+      return false;
+    }
+    old_expanded = true;
+    bytes_needed -= uncommitted_in_old;
+    if (bytes_needed == 0) {
+      return true;
+    }
+  }
+
+  size_t bytes_to_add_in_old = 0;
+
+  // 2. Get uncommitted memory from Young virtualspace.
+  size_t young_uncommitted = MIN2(young_vs()->uncommitted_size(), bytes_needed);
+  if (young_uncommitted > 0) {
+    young_vs()->set_reserved(young_vs()->reserved_low_addr() + young_uncommitted,
+                             young_vs()->reserved_high_addr(),
+                             young_vs()->special());
+    bytes_needed -= young_uncommitted;
+    bytes_to_add_in_old = young_uncommitted;
+  }
+
+  // 3. Get committed memory from Young virtualspace
+  if (bytes_needed > 0) {
+    size_t shrink_size = align_down(bytes_needed, young_vs()->alignment());
+    bool ret = young_vs()->shrink_by(shrink_size);
+    assert(ret, "We should be able to shrink young space");
+    young_vs()->set_reserved(young_vs()->reserved_low_addr() + shrink_size,
+                             young_vs()->reserved_high_addr(),
+                             young_vs()->special());
+
+    bytes_to_add_in_old += shrink_size;
+  }
+
+  // 4. Increase size of old space
+  old_vs()->set_reserved(old_vs()->reserved_low_addr(),
+                         old_vs()->reserved_high_addr() + bytes_to_add_in_old,
+                         old_vs()->special());
+  if (!old_vs()->expand_by(bytes_to_add_in_old) && !old_expanded) {
+    return false;
+  }
+
+  DEBUG_ONLY(size_t total_size_after = young_vs()->reserved_size() + old_vs()->reserved_size());
+  assert(total_size_after == total_size_before, "should be equal");
+
+  return true;
+}
+
+// Read comment for adjust_boundary_up()
+// Increase young generation size and decrease old generation size by same amount.
+bool AdjoiningGenerationsForHeteroHeap::HeteroVirtualSpaces::adjust_boundary_down(size_t change_in_bytes) {
+  assert(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary, "runtime check");
+  DEBUG_ONLY(size_t total_size_before = young_vs()->reserved_size() + old_vs()->reserved_size());
+
+  size_t bytes_needed = change_in_bytes;
+  size_t uncommitted_in_young = MIN2(young_vs()->uncommitted_size(), bytes_needed);
+  bool young_expanded = false;
+
+  // 1. Try to expand old within its reserved space.
+  if (uncommitted_in_young > 0) {
+    if (!young_vs()->expand_by(uncommitted_in_young)) {
+      return false;
+    }
+    young_expanded = true;
+    bytes_needed -= uncommitted_in_young;
+    if (bytes_needed == 0) {
+      return true;
+    }
+  }
+
+  size_t bytes_to_add_in_young = 0;
+
+  // 2. Get uncommitted memory from Old virtualspace.
+  size_t old_uncommitted = MIN2(old_vs()->uncommitted_size(), bytes_needed);
+  if (old_uncommitted > 0) {
+    old_vs()->set_reserved(old_vs()->reserved_low_addr(),
+                           old_vs()->reserved_high_addr() - old_uncommitted,
+                           old_vs()->special());
+    bytes_needed -= old_uncommitted;
+    bytes_to_add_in_young = old_uncommitted;
+  }
+
+  // 3. Get committed memory from Old virtualspace
+  if (bytes_needed > 0) {
+    size_t shrink_size = align_down(bytes_needed, old_vs()->alignment());
+    bool ret = old_vs()->shrink_by(shrink_size);
+    assert(ret, "We should be able to shrink young space");
+           old_vs()->set_reserved(old_vs()->reserved_low_addr(),
+           old_vs()->reserved_high_addr() - shrink_size,
+           old_vs()->special());
+
+    bytes_to_add_in_young += shrink_size;
+  }
+
+  assert(bytes_to_add_in_young <= change_in_bytes, "should not be more than requested size");
+  // 4. Increase size of young space
+  young_vs()->set_reserved(young_vs()->reserved_low_addr() - bytes_to_add_in_young,
+                           young_vs()->reserved_high_addr(),
+                           young_vs()->special());
+  if (!young_vs()->expand_by(bytes_to_add_in_young) && !young_expanded) {
+    return false;
+  }
+
+  DEBUG_ONLY(size_t total_size_after = young_vs()->reserved_size() + old_vs()->reserved_size());
+  assert(total_size_after == total_size_before, "should be equal");
+
+  return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerationsForHeteroHeap.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP
+#define SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP
+
+#include "gc/parallel/adjoiningGenerations.hpp"
+
+class AdjoiningGenerationsForHeteroHeap : public AdjoiningGenerations {
+  friend class VMStructs;
+private:
+  // Maximum total size of the generations. This is equal to the heap size specified by user.
+  // When adjusting young and old generation sizes, we need ensure that sum of the generation sizes does not exceed this.
+  size_t _total_size_limit;
+
+  size_t total_size_limit() const {
+    return _total_size_limit;
+  }
+
+  // HeteroVirtualSpaces creates non-overlapping virtual spaces. Here _low and _high do not share a reserved space, i.e. there is no boundary
+  // separating the two virtual spaces.
+  class HeteroVirtualSpaces : public AdjoiningVirtualSpaces {
+    size_t _max_total_size;
+    size_t _min_old_byte_size;
+    size_t _min_young_byte_size;
+    size_t _max_old_byte_size;
+    size_t _max_young_byte_size;
+
+    // Internally we access the virtual spaces using these methods. It increases readability, since we were not really
+    // dealing with adjoining virtual spaces separated by a boundary as is the case in base class.
+    // Externally they are accessed using low() and high() methods of base class.
+    PSVirtualSpace* young_vs() { return high(); }
+    PSVirtualSpace* old_vs() { return low(); }
+
+  public:
+    HeteroVirtualSpaces(ReservedSpace rs,
+                        size_t min_old_byte_size,
+                        size_t min_young_byte_size, size_t max_total_size,
+                        size_t alignment);
+
+    // Increase old generation size and decrease young generation size by same amount
+    bool adjust_boundary_up(size_t size_in_bytes);
+    // Increase young generation size and decrease old generation size by same amount
+    bool adjust_boundary_down(size_t size_in_bytes);
+
+    size_t max_young_size() const { return _max_young_byte_size; }
+    size_t max_old_size() const { return _max_old_byte_size; }
+
+    void initialize(size_t initial_old_reserved_size, size_t init_low_byte_size,
+                    size_t init_high_byte_size);
+  };
+
+public:
+  AdjoiningGenerationsForHeteroHeap(ReservedSpace rs, GenerationSizer* policy, size_t alignment);
+
+  // Given the size policy, calculate the total amount of memory that needs to be reserved.
+  // We need to reserve more memory than Xmx, since we use non-overlapping virtual spaces for the young and old generations.
+  static size_t required_reserved_memory(GenerationSizer* policy);
+
+  // Return the total byte size of the reserved space
+  size_t reserved_byte_size();
+};
+#endif // SHARE_VM_GC_PARALLEL_ADJOININGGENERATIONSFORHETEROHEAP_HPP
+
--- a/src/hotspot/share/gc/parallel/adjoiningVirtualSpaces.hpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/adjoiningVirtualSpaces.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -59,7 +59,8 @@
 // moved up consistently.  AdjoiningVirtualSpaces provide the
 // interfaces for moving the this boundary.
 
-class AdjoiningVirtualSpaces {
+class AdjoiningVirtualSpaces : public CHeapObj<mtGC> {
+protected:
   // space at the high end and the low end, respectively
   PSVirtualSpace*    _high;
   PSVirtualSpace*    _low;
@@ -84,17 +85,17 @@
                          size_t alignment);
 
   // accessors
-  PSVirtualSpace* high() { return _high; }
-  PSVirtualSpace* low()  { return _low; }
+  virtual PSVirtualSpace* high() { return _high; }
+  virtual PSVirtualSpace* low()  { return _low; }
   ReservedSpace reserved_space() { return _reserved_space; }
   size_t min_low_byte_size() { return _min_low_byte_size; }
   size_t min_high_byte_size() { return _min_high_byte_size; }
   size_t alignment() const { return _alignment; }
 
   // move boundary between the two spaces up
-  bool adjust_boundary_up(size_t size_in_bytes);
+  virtual bool adjust_boundary_up(size_t size_in_bytes);
   // and down
-  bool adjust_boundary_down(size_t size_in_bytes);
+  virtual bool adjust_boundary_down(size_t size_in_bytes);
 
   // Maximum byte size for the high space.
   size_t high_byte_size_limit() {
@@ -107,9 +108,8 @@
 
   // Sets the boundaries for the virtual spaces and commits and
   // initial size;
-  void initialize(size_t max_low_byte_size,
+  virtual void initialize(size_t max_low_byte_size,
                   size_t init_low_byte_size,
                   size_t init_high_byte_size);
 };
-
 #endif // SHARE_VM_GC_PARALLEL_ADJOININGVIRTUALSPACES_HPP
--- a/src/hotspot/share/gc/parallel/generationSizer.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/generationSizer.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -67,3 +67,11 @@
   }
   GenCollectorPolicy::initialize_size_info();
 }
+
+bool GenerationSizer::is_hetero_heap() const {
+  return false;
+}
+
+size_t GenerationSizer::heap_reserved_size_bytes() const {
+  return _max_heap_byte_size;
+}
--- a/src/hotspot/share/gc/parallel/generationSizer.hpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/generationSizer.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -32,7 +32,6 @@
 
 class GenerationSizer : public GenCollectorPolicy {
  private:
-
   // The alignment used for boundary between young gen and old gen
   static size_t default_gen_alignment() { return 64 * K * HeapWordSize; }
 
@@ -41,5 +40,9 @@
   void initialize_alignments();
   void initialize_flags();
   void initialize_size_info();
+
+ public:
+  virtual size_t heap_reserved_size_bytes() const;
+  virtual bool is_hetero_heap() const;
 };
 #endif // SHARE_VM_GC_PARALLEL_GENERATIONSIZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/heterogeneousGenerationSizer.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018, 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/parallel/heterogeneousGenerationSizer.hpp"
+#include "gc/shared/collectorPolicy.hpp"
+#include "logging/log.hpp"
+#include "runtime/globals_extension.hpp"
+#include "runtime/os.hpp"
+#include "utilities/align.hpp"
+#include "utilities/formatBuffer.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+const double HeterogeneousGenerationSizer::MaxRamFractionForYoung = 0.8;
+
+// Check the available dram memory to limit NewSize and MaxNewSize before
+// calling base class initialize_flags().
+void HeterogeneousGenerationSizer::initialize_flags() {
+  FormatBuffer<100> calc_str("");
+
+  julong phys_mem;
+  // If MaxRam is specified, we use that as maximum physical memory available.
+  if (FLAG_IS_DEFAULT(MaxRAM)) {
+    phys_mem = os::physical_memory();
+    calc_str.append("Physical_Memory");
+  } else {
+    phys_mem = (julong)MaxRAM;
+    calc_str.append("MaxRAM");
+  }
+
+  julong reasonable_max = phys_mem;
+
+  // If either MaxRAMFraction or MaxRAMPercentage is specified, we use them to calculate
+  // reasonable max size of young generation.
+  if (!FLAG_IS_DEFAULT(MaxRAMFraction)) {
+    reasonable_max = (julong)(phys_mem / MaxRAMFraction);
+    calc_str.append(" / MaxRAMFraction");
+  } else if (!FLAG_IS_DEFAULT(MaxRAMPercentage)) {
+    reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
+    calc_str.append(" * MaxRAMPercentage / 100");
+  } else {
+    // We use our own fraction to calculate max size of young generation.
+    reasonable_max = phys_mem * MaxRamFractionForYoung;
+    calc_str.append(" * %0.2f", MaxRamFractionForYoung);
+  }
+  reasonable_max = align_up(reasonable_max, _gen_alignment);
+
+  if (MaxNewSize > reasonable_max) {
+    if (FLAG_IS_CMDLINE(MaxNewSize)) {
+      log_warning(gc, ergo)("Setting MaxNewSize to " SIZE_FORMAT " based on dram available (calculation = align(%s))",
+                            (size_t)reasonable_max, calc_str.buffer());
+    } else {
+      log_info(gc, ergo)("Setting MaxNewSize to " SIZE_FORMAT " based on dram available (calculation = align(%s)). "
+                         "Dram usage can be lowered by setting MaxNewSize to a lower value", (size_t)reasonable_max, calc_str.buffer());
+    }
+    MaxNewSize = reasonable_max;
+  }
+  if (NewSize > reasonable_max) {
+    if (FLAG_IS_CMDLINE(NewSize)) {
+      log_warning(gc, ergo)("Setting NewSize to " SIZE_FORMAT " based on dram available (calculation = align(%s))",
+                            (size_t)reasonable_max, calc_str.buffer());
+    }
+    NewSize = reasonable_max;
+  }
+
+  // After setting new size flags, call base class initialize_flags()
+  GenerationSizer::initialize_flags();
+}
+
+bool HeterogeneousGenerationSizer::is_hetero_heap() const {
+  return true;
+}
+
+size_t HeterogeneousGenerationSizer::heap_reserved_size_bytes() const {
+  if (UseAdaptiveGCBoundary) {
+    // This is the size that young gen can grow to, when UseAdaptiveGCBoundary is true.
+    size_t max_yg_size = _max_heap_byte_size - _min_old_size;
+    // This is the size that old gen can grow to, when UseAdaptiveGCBoundary is true.
+    size_t max_old_size = _max_heap_byte_size - _min_young_size;
+
+    return max_yg_size + max_old_size;
+  } else {
+    return _max_heap_byte_size;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/heterogeneousGenerationSizer.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_PARALLEL_HETEROGENEOUSGENERATIONSIZER_HPP
+#define SHARE_VM_GC_PARALLEL_HETEROGENEOUSGENERATIONSIZER_HPP
+
+#include "gc/parallel/generationSizer.hpp"
+
+// There is a nice batch of tested generation sizing code in
+// GenCollectorPolicy. Lets reuse it!
+
+class HeterogeneousGenerationSizer : public GenerationSizer {
+private:
+  // Max fraction of dram to use for young generation when MaxRAMFraction and
+  // MaxRAMPercentage are not specified on commandline.
+  static const double MaxRamFractionForYoung;
+
+protected:
+  virtual void initialize_flags();
+
+public:
+  virtual size_t heap_reserved_size_bytes() const;
+  virtual bool is_hetero_heap() const;
+};
+#endif // SHARE_VM_GC_PARALLEL_HETEROGENEOUSGENERATIONSIZER_HPP
--- a/src/hotspot/share/gc/parallel/parallelArguments.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -24,6 +24,7 @@
  */
 
 #include "precompiled.hpp"
+#include "gc/parallel/heterogeneousGenerationSizer.hpp"
 #include "gc/parallel/parallelArguments.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
 #include "gc/shared/adaptiveSizePolicy.hpp"
@@ -93,5 +94,9 @@
 }
 
 CollectedHeap* ParallelArguments::create_heap() {
-  return create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
+  if (AllocateOldGenAt != NULL) {
+    return create_heap_with_policy<ParallelScavengeHeap, HeterogeneousGenerationSizer>();
+  } else {
+    return create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
+  }
 }
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "code/codeCache.hpp"
 #include "gc/parallel/adjoiningGenerations.hpp"
+#include "gc/parallel/adjoiningGenerationsForHeteroHeap.hpp"
 #include "gc/parallel/adjoiningVirtualSpaces.hpp"
 #include "gc/parallel/gcTaskManager.hpp"
 #include "gc/parallel/generationSizer.hpp"
@@ -58,7 +59,7 @@
 GCTaskManager* ParallelScavengeHeap::_gc_task_manager = NULL;
 
 jint ParallelScavengeHeap::initialize() {
-  const size_t heap_size = _collector_policy->max_heap_byte_size();
+  size_t heap_size = _collector_policy->heap_reserved_size_bytes();
 
   ReservedSpace heap_rs = Universe::reserve_heap(heap_size, _collector_policy->heap_alignment());
 
@@ -86,7 +87,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, _collector_policy, generation_alignment());
+  _gens = AdjoiningGenerations::create_adjoining_generations(heap_rs, _collector_policy, generation_alignment());
 
   _old_gen = _gens->old_gen();
   _young_gen = _gens->young_gen();
@@ -104,7 +105,7 @@
                              GCTimeRatio
                              );
 
-  assert(!UseAdaptiveGCBoundary ||
+  assert(_collector_policy->is_hetero_heap() || !UseAdaptiveGCBoundary ||
     (old_gen()->virtual_space()->high_boundary() ==
      young_gen()->virtual_space()->low_boundary()),
     "Boundaries must meet");
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -111,6 +111,8 @@
 
   virtual CollectorPolicy* collector_policy() const { return _collector_policy; }
 
+  virtual GenerationSizer* ps_collector_policy() const { return _collector_policy; }
+
   virtual SoftRefPolicy* soft_ref_policy() { return &_soft_ref_policy; }
 
   virtual GrowableArray<GCMemoryManager*> memory_managers();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018, 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/parallel/psFileBackedVirtualspace.hpp"
+#include "memory/virtualspace.hpp"
+#include "runtime/os.inline.hpp"
+
+PSFileBackedVirtualSpace::PSFileBackedVirtualSpace(ReservedSpace rs, size_t alignment, const char* path) : PSVirtualSpace(rs, alignment),
+                                                   _file_path(path), _fd(-1), _mapping_succeeded(false) {
+  assert(!rs.special(), "ReservedSpace passed to PSFileBackedVirtualSpace cannot be special");
+}
+
+bool PSFileBackedVirtualSpace::initialize() {
+  _fd = os::create_file_for_heap(_file_path);
+  if (_fd == -1) {
+    return false;
+  }
+  // We map the reserved space to a file at initialization.
+  char* ret = os::replace_existing_mapping_with_file_mapping(reserved_low_addr(), reserved_size(), _fd);
+  if (ret != reserved_low_addr()) {
+    os::close(_fd);
+    return false;
+  }
+  // _mapping_succeeded is false if we return before this point.
+  // expand calls later check value of this flag and return error if it is false.
+  _mapping_succeeded = true;
+  _special = true;
+  os::close(_fd);
+  return true;
+}
+
+PSFileBackedVirtualSpace::PSFileBackedVirtualSpace(ReservedSpace rs, const char* path) {
+  PSFileBackedVirtualSpace(rs, os::vm_page_size(), path);
+}
+
+bool PSFileBackedVirtualSpace::expand_by(size_t bytes) {
+  assert(special(), "Since entire space is committed at initialization, _special should always be true for PSFileBackedVirtualSpace");
+
+  // if mapping did not succeed during intialization return false
+  if (!_mapping_succeeded) {
+    return false;
+  }
+  return PSVirtualSpace::expand_by(bytes);
+
+}
+
+bool PSFileBackedVirtualSpace::shrink_by(size_t bytes) {
+  assert(special(), "Since entire space is committed at initialization, _special should always be true for PSFileBackedVirtualSpace");
+  return PSVirtualSpace::shrink_by(bytes);
+}
+
+size_t PSFileBackedVirtualSpace::expand_into(PSVirtualSpace* space, size_t bytes) {
+  // not supported. Since doing this will change page mapping which will lead to large TLB penalties.
+  assert(false, "expand_into() should not be called for PSFileBackedVirtualSpace");
+  return 0;
+}
+
+void PSFileBackedVirtualSpace::release() {
+  os::close(_fd);
+  _fd = -1;
+  _file_path = NULL;
+
+  PSVirtualSpace::release();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp	Fri Dec 21 08:23:55 2018 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP
+#define SHARE_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP
+
+#include "gc/parallel/psVirtualspace.hpp"
+
+class PSFileBackedVirtualSpace : public PSVirtualSpace {
+private:
+  const char* _file_path;
+  int _fd;
+  bool _mapping_succeeded;
+public:
+  PSFileBackedVirtualSpace(ReservedSpace rs, size_t alignment, const char* file_path);
+  PSFileBackedVirtualSpace(ReservedSpace rs, const char* file_path);
+
+  bool   initialize();
+  bool   expand_by(size_t bytes);
+  bool   shrink_by(size_t bytes);
+  size_t expand_into(PSVirtualSpace* space, size_t bytes);
+  void   release();
+};
+#endif // SHARE_VM_GC_PARALLEL_PSFILEBACKEDVIRTUALSPACE_HPP
+
--- a/src/hotspot/share/gc/parallel/psOldGen.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/psOldGen.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -27,6 +27,7 @@
 #include "gc/parallel/parallelScavengeHeap.hpp"
 #include "gc/parallel/psAdaptiveSizePolicy.hpp"
 #include "gc/parallel/psCardTable.hpp"
+#include "gc/parallel/psFileBackedVirtualspace.hpp"
 #include "gc/parallel/psMarkSweepDecorator.hpp"
 #include "gc/parallel/psOldGen.hpp"
 #include "gc/shared/cardTableBarrierSet.hpp"
@@ -71,7 +72,14 @@
 
 void PSOldGen::initialize_virtual_space(ReservedSpace rs, size_t alignment) {
 
-  _virtual_space = new PSVirtualSpace(rs, alignment);
+  if(ParallelScavengeHeap::heap()->ps_collector_policy()->is_hetero_heap()) {
+    _virtual_space = new PSFileBackedVirtualSpace(rs, alignment, AllocateOldGenAt);
+    if (!(static_cast <PSFileBackedVirtualSpace*>(_virtual_space))->initialize()) {
+      vm_exit_during_initialization("Could not map space for PSOldGen at given AllocateOldGenAt path");
+    }
+  } else {
+    _virtual_space = new PSVirtualSpace(rs, alignment);
+  }
   if (!_virtual_space->expand_by(_init_gen_size)) {
     vm_exit_during_initialization("Could not reserve enough space for "
                                   "object heap");
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -1995,7 +1995,10 @@
   assert(young_gen->virtual_space()->alignment() ==
          old_gen->virtual_space()->alignment(), "alignments do not match");
 
-  if (!(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary)) {
+  // We also return false when it's a heterogenous heap because old generation cannot absorb data from eden
+  // when it is allocated on different memory (example, nv-dimm) than young.
+  if (!(UseAdaptiveSizePolicy && UseAdaptiveGCBoundary) ||
+      ParallelScavengeHeap::heap()->ps_collector_policy()->is_hetero_heap()) {
     return false;
   }
 
--- a/src/hotspot/share/prims/whitebox.cpp	Fri Dec 21 08:18:59 2018 -0800
+++ b/src/hotspot/share/prims/whitebox.cpp	Fri Dec 21 08:23:55 2018 -0800
@@ -500,7 +500,7 @@
 
 #endif // INCLUDE_G1GC
 
-#if INCLUDE_G1GC
+#if INCLUDE_G1GC || INCLUDE_PARALLELGC
 WB_ENTRY(jlong, WB_DramReservedStart(JNIEnv* env, jobject o))
   if (UseG1GC) {
     G1CollectedHeap* g1h = G1CollectedHeap::heap();
@@ -511,7 +511,16 @@
       return (jlong)g1h->base();
     }
   }
-  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_DramReservedStart: enabled only for G1");
+  if (UseParallelGC) {
+    ParallelScavengeHeap* ps_heap = ParallelScavengeHeap::heap();
+    if (AllocateOldGenAt != NULL) {
+      MemRegion reserved = ps_heap->young_gen()->reserved();
+      return (jlong)reserved.start();
+    } else {
+      return (jlong)ps_heap->base();
+    }
+  }
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_DramReservedStart: enabled only for G1 and Parallel GC");
 WB_END
 
 WB_ENTRY(jlong, WB_DramReservedEnd(JNIEnv* env, jobject o))
@@ -524,7 +533,16 @@
       return (jlong)g1h->base() + g1h->collector_policy()->max_heap_byte_size();
     }
   }
-  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_DramReservedEnd: enabled only for G1");
+  if (UseParallelGC) {
+    ParallelScavengeHeap* ps_heap = ParallelScavengeHeap::heap();
+    if (AllocateOldGenAt != NULL) {
+      MemRegion reserved = ps_heap->young_gen()->reserved();
+      return (jlong)reserved.end();
+    } else {
+      return (jlong)ps_heap->reserved_region().end();
+    }
+  }
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_DramReservedEnd: enabled only for G1 and Parallel GC");
 WB_END
 
 WB_ENTRY(jlong, WB_NvdimmReservedStart(JNIEnv* env, jobject o))
@@ -537,7 +555,16 @@
       THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedStart: Old gen is not allocated on NV-DIMM using AllocateOldGenAt flag");
     }
   }
-  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedStart: enabled only for G1");
+  if (UseParallelGC) {
+    ParallelScavengeHeap* ps_heap = ParallelScavengeHeap::heap();
+    if (AllocateOldGenAt != NULL) {
+      MemRegion reserved = ps_heap->old_gen()->reserved();
+      return (jlong)reserved.start();
+    } else {
+      THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedStart: Old gen is not allocated on NV-DIMM using AllocateOldGenAt flag");
+    }
+  }
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedStart: enabled only for G1 and Parallel GC");
 WB_END
 
 WB_ENTRY(jlong, WB_NvdimmReservedEnd(JNIEnv* env, jobject o))
@@ -550,10 +577,19 @@
       THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedEnd: Old gen is not allocated on NV-DIMM using AllocateOldGenAt flag");
     }
   }
-  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedEnd: enabled only for G1");
+  if (UseParallelGC) {
+    ParallelScavengeHeap* ps_heap = ParallelScavengeHeap::heap();
+    if (AllocateOldGenAt != NULL) {
+      MemRegion reserved = ps_heap->old_gen()->reserved();
+      return (jlong)reserved.end();
+      } else {
+      THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedEnd: Old gen is not allocated on NV-DIMM using AllocateOldGenAt flag");
+    }
+  }
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_NvdimmReservedEnd: enabled only for G1 and Parallel GC");
 WB_END
 
-#endif // INCLUDE_G1GC
+#endif // INCLUDE_G1GC || INCLUDE_PARALLELGC
 
 #if INCLUDE_PARALLELGC
 
@@ -2109,11 +2145,13 @@
   {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;",
                                                       (void*)&WB_G1AuxiliaryMemoryUsage  },
   {CC"g1GetMixedGCInfo",   CC"(I)[J",                 (void*)&WB_G1GetMixedGCInfo },
+#endif // INCLUDE_G1GC
+#if INCLUDE_G1GC || INCLUDE_PARALLELGC
   {CC"dramReservedStart",   CC"()J",                  (void*)&WB_DramReservedStart },
   {CC"dramReservedEnd",     CC"()J",                  (void*)&WB_DramReservedEnd },
   {CC"nvdimmReservedStart", CC"()J",                  (void*)&WB_NvdimmReservedStart },
   {CC"nvdimmReservedEnd",   CC"()J",                  (void*)&WB_NvdimmReservedEnd },
-#endif // INCLUDE_G1GC
+#endif // INCLUDE_G1GC || INCLUDE_PARALLELGC
 #if INCLUDE_PARALLELGC
   {CC"psVirtualSpaceAlignment",CC"()J",               (void*)&WB_PSVirtualSpaceAlignment},
   {CC"psHeapGenerationAlignment",CC"()J",             (void*)&WB_PSHeapGenerationAlignment},
--- a/test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAt.java	Fri Dec 21 08:18:59 2018 -0800
+++ b/test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAt.java	Fri Dec 21 08:23:55 2018 -0800
@@ -54,6 +54,8 @@
                                                  "-version"});
 
     runTest("-XX:+UseG1GC");
+    runTest("-XX:+UseParallelOldGC -XX:-UseAdaptiveGCBoundary");
+    runTest("-XX:+UseParallelOldGC -XX:+UseAdaptiveGCBoundary");
   }
 
   private static void runTest(String... extraFlags) throws Exception {
--- a/test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAtError.java	Fri Dec 21 08:18:59 2018 -0800
+++ b/test/hotspot/jtreg/gc/nvdimm/TestAllocateOldGenAtError.java	Fri Dec 21 08:23:55 2018 -0800
@@ -63,6 +63,7 @@
                                                  "-version"});
 
     testG1();
+    testParallelOld();
   }
 
   private static void testG1() throws Exception {
@@ -73,6 +74,19 @@
     output.shouldContain("Could not initialize G1 heap");
     output.shouldContain("Error occurred during initialization of VM");
     output.shouldNotHaveExitValue(0);
+
+  }
+
+  private static void testParallelOld() throws Exception {
+    System.out.println("Testing ParallelOld GC with UseAdaptiveGCBoundary disabled");
+    OutputAnalyzer output = runTest("-XX:+UseParallelOldGC -XX:-UseAdaptiveGCBoundary");
+    output.shouldContain("Error occurred during initialization of VM");
+    output.shouldNotHaveExitValue(0);
+
+    System.out.println("Testing ParallelOld GC with UseAdaptiveGCBoundary enabled");
+    output = runTest("-XX:+UseParallelOldGC -XX:+UseAdaptiveGCBoundary");
+    output.shouldContain("Error occurred during initialization of VM");
+    output.shouldNotHaveExitValue(0);
   }
 
   private static OutputAnalyzer runTest(String... extraFlags) throws Exception {
--- a/test/hotspot/jtreg/gc/nvdimm/TestOldObjectsOnNvdimm.java	Fri Dec 21 08:18:59 2018 -0800
+++ b/test/hotspot/jtreg/gc/nvdimm/TestOldObjectsOnNvdimm.java	Fri Dec 21 08:23:55 2018 -0800
@@ -72,6 +72,9 @@
 
         // Test with G1 GC
         runTest("-XX:+UseG1GC");
+        // Test with ParallelOld GC
+        runTest("-XX:+UseParallelOldGC -XX:-UseAdaptiveGCBoundary");
+        runTest("-XX:+UseParallelOldGC -XX:+UseAdaptiveGCBoundary");
     }
 
     private static void runTest(String... extraFlags) throws Exception {
--- a/test/hotspot/jtreg/gc/nvdimm/TestYoungObjectsOnDram.java	Fri Dec 21 08:18:59 2018 -0800
+++ b/test/hotspot/jtreg/gc/nvdimm/TestYoungObjectsOnDram.java	Fri Dec 21 08:23:55 2018 -0800
@@ -73,6 +73,9 @@
 
         // Test with G1 GC
         runTest("-XX:+UseG1GC");
+        // Test with ParallelOld GC
+        runTest("-XX:+UseParallelOldGC -XX:-UseAdaptiveGCBoundary");
+        runTest("-XX:+UseParallelOldGC -XX:+UseAdaptiveGCBoundary");
     }
 
     private static void runTest(String... extraFlags) throws Exception {