8202842: G1 footprint regressions in jdk11+10
authortschatzl
Mon, 28 May 2018 11:13:21 +0200
changeset 50281 bc1336220671
parent 50280 5aaf3a471172
child 50282 4887e76f2493
child 50283 2f9811d99ba8
8202842: G1 footprint regressions in jdk11+10 Summary: Lazily initialize G1FromCardCache to save on startup footprint if AlwaysPretouch is disabled. Reviewed-by: sjohanss, redestad
src/hotspot/share/gc/g1/g1CollectedHeap.cpp
src/hotspot/share/gc/g1/g1FromCardCache.cpp
src/hotspot/share/gc/g1/g1FromCardCache.hpp
src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp
src/hotspot/share/memory/padded.hpp
src/hotspot/share/memory/padded.inline.hpp
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Mon May 28 11:13:21 2018 +0200
@@ -1611,6 +1611,9 @@
   const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1;
   guarantee((max_regions() - 1) <= max_region_idx, "too many regions");
 
+  // The G1FromCardCache reserves card with value 0 as "invalid", so the heap must not
+  // start within the first card.
+  guarantee(g1_rs.base() >= (char*)G1CardTable::card_size, "Java heap must not start within the first card.");
   // Also create a G1 rem set.
   _g1_rem_set = new G1RemSet(this, _card_table, _hot_card_cache);
   _g1_rem_set->initialize(max_capacity(), max_regions());
--- a/src/hotspot/share/gc/g1/g1FromCardCache.cpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1FromCardCache.cpp	Mon May 28 11:13:21 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, 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
@@ -47,7 +47,9 @@
                                                              num_par_rem_sets,
                                                              &_static_mem_size);
 
-  invalidate(0, _max_regions);
+  if (AlwaysPreTouch) {
+    invalidate(0, _max_regions);
+  }
 }
 
 void G1FromCardCache::invalidate(uint start_idx, size_t new_num_regions) {
--- a/src/hotspot/share/gc/g1/g1FromCardCache.hpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1FromCardCache.hpp	Mon May 28 11:13:21 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,7 +31,7 @@
 // G1FromCardCache remembers the most recently processed card on the heap on
 // a per-region and per-thread basis.
 class G1FromCardCache : public AllStatic {
- private:
+private:
   // Array of card indices. Indexed by heap region (rows) and thread (columns) to minimize
   // thread contention.
   // This order minimizes the time to clear all entries for a given region during region
@@ -49,9 +49,12 @@
   }
 #endif
 
- public:
-  static const uintptr_t InvalidCard = UINTPTR_MAX;
+  // This card index indicates "no card for that entry" yet. This allows us to use the OS
+  // lazy backing of memory with zero-filled pages to avoid initial actual memory use.
+  // This means that the heap must not contain card zero.
+  static const uintptr_t InvalidCard = 0;
 
+public:
   static void clear(uint region_idx);
 
   // Returns true if the given card is in the cache at the given location, or
--- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp	Mon May 28 11:13:21 2018 +0200
@@ -36,9 +36,6 @@
   guarantee(is_power_of_2(num_cache_entries),
             "Number of cache entries must be power of two, but is %u", num_cache_entries);
   _cache = NEW_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, _num_cache_entries, mtGC);
-  for (uint i = 0; i < _num_cache_entries; i++) {
-    _cache[i].clear();
-  }
   _num_cache_entries_mask = _num_cache_entries - 1;
 }
 
--- a/src/hotspot/share/memory/padded.hpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/memory/padded.hpp	Mon May 28 11:13:21 2018 +0200
@@ -104,6 +104,8 @@
  public:
   // Creates an aligned padded 2D array.
   // The memory cannot be deleted since the raw memory chunk is not returned.
+  // Always uses mmap to reserve memory. Only the first few pages with the index to
+  // the rows are touched. Allocation size should be "large" to cover page overhead.
   static T** create_unfreeable(uint rows, uint columns, size_t* allocation_size = NULL);
 };
 
--- a/src/hotspot/share/memory/padded.inline.hpp	Mon May 28 09:59:11 2018 +0200
+++ b/src/hotspot/share/memory/padded.inline.hpp	Mon May 28 11:13:21 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -62,9 +62,8 @@
   size_t total_size = table_size + rows * row_size + alignment;
 
   // Allocate a chunk of memory large enough to allow alignment of the chunk.
-  void* chunk = AllocateHeap(total_size, flags);
+  void* chunk = MmapArrayAllocator<uint8_t>::allocate(total_size, flags);
   // Clear the allocated memory.
-  memset(chunk, 0, total_size);
   // Align the chunk of memory.
   T** result = (T**)align_up(chunk, alignment);
   void* data_start = (void*)((uintptr_t)result + table_size);