8143587: G1 crashes with humongous object of size that almost fills a heap region
authordavid
Tue, 24 Nov 2015 14:03:42 +0100
changeset 34291 8ad97a2bc8e7
parent 34284 32543d155516
child 34292 e005cf237e46
8143587: G1 crashes with humongous object of size that almost fills a heap region Reviewed-by: mgerdin, brutisso
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Nov 25 04:51:32 2015 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Tue Nov 24 14:03:42 2015 +0100
@@ -301,8 +301,8 @@
   assert(is_humongous(word_size), "word_size should be humongous");
   assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition");
 
-  // Index of last region in the series + 1.
-  uint last = first + num_regions;
+  // Index of last region in the series.
+  uint last = first + num_regions - 1;
 
   // We need to initialize the region(s) we just discovered. This is
   // a bit tricky given that it can happen concurrently with
@@ -339,23 +339,30 @@
   // thread to calculate the object size incorrectly.
   Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
 
-  size_t fill_size = word_size_sum - word_size;
-  if (fill_size >= min_fill_size()) {
-    fill_with_objects(obj_top, fill_size);
-  } else {
-    fill_size = 0;
+  // How many words we use for filler objects.
+  size_t word_fill_size = word_size_sum - word_size;
+
+  // How many words memory we "waste" which cannot hold a filler object.
+  size_t words_not_fillable = 0;
+
+  if (word_fill_size >= min_fill_size()) {
+    fill_with_objects(obj_top, word_fill_size);
+  } else if (word_fill_size > 0) {
+    // We have space to fill, but we cannot fit an object there.
+    words_not_fillable = word_fill_size;
+    word_fill_size = 0;
   }
 
   // We will set up the first region as "starts humongous". This
   // will also update the BOT covering all the regions to reflect
   // that there is a single object that starts at the bottom of the
   // first region.
-  first_hr->set_starts_humongous(obj_top, fill_size);
+  first_hr->set_starts_humongous(obj_top, word_fill_size);
   first_hr->set_allocation_context(context);
   // Then, if there are any, we will set up the "continues
   // humongous" regions.
   HeapRegion* hr = NULL;
-  for (uint i = first + 1; i < last; ++i) {
+  for (uint i = first + 1; i <= last; ++i) {
     hr = region_at(i);
     hr->set_continues_humongous(first_hr);
     hr->set_allocation_context(context);
@@ -370,33 +377,38 @@
   // object header and the BOT initialization.
   OrderAccess::storestore();
 
-  // Now that the BOT and the object header have been initialized,
-  // we can update top of the "starts humongous" region.
-  first_hr->set_top(first_hr->end());
-  if (_hr_printer.is_active()) {
-    _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->end());
-  }
-
   // Now, we will update the top fields of the "continues humongous"
-  // regions.
-  hr = NULL;
-  for (uint i = first + 1; i < last; ++i) {
+  // regions except the last one.
+  for (uint i = first; i < last; ++i) {
     hr = region_at(i);
     hr->set_top(hr->end());
-    if (_hr_printer.is_active()) {
-      _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
-    }
-  }
-
-  assert(hr == NULL || (hr->bottom() < obj_top && obj_top <= hr->end()),
+  }
+
+  hr = region_at(last);
+  // If we cannot fit a filler object, we must set top to the end
+  // of the humongous object, otherwise we cannot iterate the heap
+  // and the BOT will not be complete.
+  hr->set_top(hr->end() - words_not_fillable);
+
+  assert(hr->bottom() < obj_top && obj_top <= hr->end(),
          "obj_top should be in last region");
 
   check_bitmaps("Humongous Region Allocation", first_hr);
 
-  increase_used(word_size_sum * HeapWordSize);
-
-  for (uint i = first; i < last; ++i) {
-    _humongous_set.add(region_at(i));
+  assert(words_not_fillable == 0 ||
+         first_hr->bottom() + word_size_sum - words_not_fillable == hr->top(),
+         "Miscalculation in humongous allocation");
+
+  increase_used((word_size_sum - words_not_fillable) * HeapWordSize);
+
+  for (uint i = first; i <= last; ++i) {
+    hr = region_at(i);
+    _humongous_set.add(hr);
+    if (i == first) {
+      _hr_printer.alloc(G1HRPrinter::StartsHumongous, hr, hr->top());
+    } else {
+      _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->top());
+    }
   }
 
   return new_obj;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java	Tue Nov 24 14:03:42 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 2015, 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 TestHumongousAllocNearlyFullRegion
+ * @bug 8143587
+ * @summary G1: humongous object allocations should work even when there is
+ *              not enough space in the heapRegion to fit a filler object.
+ * @library /testlibrary
+ * @run driver TestHumongousAllocNearlyFullRegion
+ */
+
+import jdk.test.lib.*;
+
+public class TestHumongousAllocNearlyFullRegion {
+    // Heap sizes < 224 MB are increased to 224 MB if vm_page_size == 64K to
+    // fulfill alignment constraints.
+    private static final int heapSize                       = 224; // MB
+    private static final int heapRegionSize                 = 1;   // MB
+
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+            "-XX:+UseG1GC",
+            "-Xms" + heapSize + "m",
+            "-Xmx" + heapSize + "m",
+            "-XX:G1HeapRegionSize=" + heapRegionSize + "m",
+            "-XX:+PrintGC",
+            HumongousObjectAllocator.class.getName());
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldContain("GC pause (G1 Humongous Allocation) (young) (initial-mark)");
+        output.shouldHaveExitValue(0);
+    }
+
+    static class HumongousObjectAllocator {
+        public static void main(String [] args) {
+            for (int i = 0; i < heapSize; i++) {
+                // 131069 is the number of longs it takes to fill a heapRegion except
+                // for 8 bytes on 64 bit.
+                long[] largeObect = new long[131069];
+            }
+        }
+    }
+}
+