hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
changeset 8103 65eafe3fb3c7
parent 8072 f223f43cd62f
child 8485 e84ccd8664ba
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Tue Feb 01 14:05:46 2011 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Feb 02 10:41:20 2011 -0800
@@ -546,8 +546,11 @@
     res = new_region_try_secondary_free_list(word_size);
   }
   if (res == NULL && do_expand) {
-    expand(word_size * HeapWordSize);
-    res = _free_list.remove_head_or_null();
+    if (expand(word_size * HeapWordSize)) {
+      // The expansion succeeded and so we should have at least one
+      // region on the free list.
+      res = _free_list.remove_head();
+    }
   }
   if (res != NULL) {
     if (G1PrintHeapRegions) {
@@ -631,9 +634,22 @@
   if (first == -1) {
     // The only thing we can do now is attempt expansion.
     if (fs + x_size >= num_regions) {
-      expand((num_regions - fs) * HeapRegion::GrainBytes);
-      first = humongous_obj_allocate_find_first(num_regions, word_size);
-      assert(first != -1, "this should have worked");
+      // If the number of regions we're trying to allocate for this
+      // object is at most the number of regions in the free suffix,
+      // then the call to humongous_obj_allocate_find_first() above
+      // should have succeeded and we wouldn't be here.
+      //
+      // We should only be trying to expand when the free suffix is
+      // not sufficient for the object _and_ we have some expansion
+      // room available.
+      assert(num_regions > fs, "earlier allocation should have succeeded");
+
+      if (expand((num_regions - fs) * HeapRegion::GrainBytes)) {
+        first = humongous_obj_allocate_find_first(num_regions, word_size);
+        // If the expansion was successful then the allocation
+        // should have been successful.
+        assert(first != -1, "this should have worked");
+      }
     }
   }
 
@@ -1647,16 +1663,17 @@
   if (capacity_after_gc < minimum_desired_capacity) {
     // Don't expand unless it's significant
     size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
-    expand(expand_bytes);
-    if (PrintGC && Verbose) {
-      gclog_or_tty->print_cr("  "
-                             "  expanding:"
-                             "  max_heap_size: %6.1fK"
-                             "  minimum_desired_capacity: %6.1fK"
-                             "  expand_bytes: %6.1fK",
-                             (double) max_heap_size / (double) K,
-                             (double) minimum_desired_capacity / (double) K,
-                             (double) expand_bytes / (double) K);
+    if (expand(expand_bytes)) {
+      if (PrintGC && Verbose) {
+        gclog_or_tty->print_cr("  "
+                               "  expanding:"
+                               "  max_heap_size: %6.1fK"
+                               "  minimum_desired_capacity: %6.1fK"
+                               "  expand_bytes: %6.1fK",
+                               (double) max_heap_size / (double) K,
+                               (double) minimum_desired_capacity / (double) K,
+                               (double) expand_bytes / (double) K);
+      }
     }
 
     // No expansion, now see if we want to shrink
@@ -1757,66 +1774,84 @@
 
   verify_region_sets_optional();
 
-  size_t expand_bytes = word_size * HeapWordSize;
-  if (expand_bytes < MinHeapDeltaBytes) {
-    expand_bytes = MinHeapDeltaBytes;
-  }
-  expand(expand_bytes);
-
-  verify_region_sets_optional();
-
-  return attempt_allocation_at_safepoint(word_size,
-                                     false /* expect_null_cur_alloc_region */);
+  size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes);
+  if (expand(expand_bytes)) {
+    verify_region_sets_optional();
+    return attempt_allocation_at_safepoint(word_size,
+                                          false /* expect_null_cur_alloc_region */);
+  }
+  return NULL;
 }
 
-// FIXME: both this and shrink could probably be more efficient by
-// doing one "VirtualSpace::expand_by" call rather than several.
-void G1CollectedHeap::expand(size_t expand_bytes) {
+bool G1CollectedHeap::expand(size_t expand_bytes) {
   size_t old_mem_size = _g1_storage.committed_size();
-  // We expand by a minimum of 1K.
-  expand_bytes = MAX2(expand_bytes, (size_t)K);
-  size_t aligned_expand_bytes =
-    ReservedSpace::page_align_size_up(expand_bytes);
+  size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
   aligned_expand_bytes = align_size_up(aligned_expand_bytes,
                                        HeapRegion::GrainBytes);
-  expand_bytes = aligned_expand_bytes;
-  while (expand_bytes > 0) {
-    HeapWord* base = (HeapWord*)_g1_storage.high();
-    // Commit more storage.
-    bool successful = _g1_storage.expand_by(HeapRegion::GrainBytes);
-    if (!successful) {
-        expand_bytes = 0;
-    } else {
-      expand_bytes -= HeapRegion::GrainBytes;
-      // Expand the committed region.
-      HeapWord* high = (HeapWord*) _g1_storage.high();
-      _g1_committed.set_end(high);
+
+  if (Verbose && PrintGC) {
+    gclog_or_tty->print("Expanding garbage-first heap from %ldK by %ldK",
+                           old_mem_size/K, aligned_expand_bytes/K);
+  }
+
+  HeapWord* old_end = (HeapWord*)_g1_storage.high();
+  bool successful = _g1_storage.expand_by(aligned_expand_bytes);
+  if (successful) {
+    HeapWord* new_end = (HeapWord*)_g1_storage.high();
+
+    // Expand the committed region.
+    _g1_committed.set_end(new_end);
+
+    // Tell the cardtable about the expansion.
+    Universe::heap()->barrier_set()->resize_covered_region(_g1_committed);
+
+    // And the offset table as well.
+    _bot_shared->resize(_g1_committed.word_size());
+
+    expand_bytes = aligned_expand_bytes;
+    HeapWord* base = old_end;
+
+    // Create the heap regions for [old_end, new_end)
+    while (expand_bytes > 0) {
+      HeapWord* high = base + HeapRegion::GrainWords;
+
       // Create a new HeapRegion.
       MemRegion mr(base, high);
       bool is_zeroed = !_g1_max_committed.contains(base);
       HeapRegion* hr = new HeapRegion(_bot_shared, mr, is_zeroed);
 
-      // Now update max_committed if necessary.
-      _g1_max_committed.set_end(MAX2(_g1_max_committed.end(), high));
-
       // Add it to the HeapRegionSeq.
       _hrs->insert(hr);
       _free_list.add_as_tail(hr);
+
       // And we used up an expansion region to create it.
       _expansion_regions--;
-      // Tell the cardtable about it.
-      Universe::heap()->barrier_set()->resize_covered_region(_g1_committed);
-      // And the offset table as well.
-      _bot_shared->resize(_g1_committed.word_size());
+
+      expand_bytes -= HeapRegion::GrainBytes;
+      base += HeapRegion::GrainWords;
+    }
+    assert(base == new_end, "sanity");
+
+    // Now update max_committed if necessary.
+    _g1_max_committed.set_end(MAX2(_g1_max_committed.end(), new_end));
+
+  } else {
+    // The expansion of the virtual storage space was unsuccessful.
+    // Let's see if it was because we ran out of swap.
+    if (G1ExitOnExpansionFailure &&
+        _g1_storage.uncommitted_size() >= aligned_expand_bytes) {
+      // We had head room...
+      vm_exit_out_of_memory(aligned_expand_bytes, "G1 heap expansion");
     }
   }
 
   if (Verbose && PrintGC) {
     size_t new_mem_size = _g1_storage.committed_size();
-    gclog_or_tty->print_cr("Expanding garbage-first heap from %ldK by %ldK to %ldK",
-                           old_mem_size/K, aligned_expand_bytes/K,
+    gclog_or_tty->print_cr("...%s, expanded to %ldK",
+                           (successful ? "Successful" : "Failed"),
                            new_mem_size/K);
   }
+  return successful;
 }
 
 void G1CollectedHeap::shrink_helper(size_t shrink_bytes)
@@ -2088,7 +2123,10 @@
   HeapRegionRemSet::init_heap(max_regions());
 
   // Now expand into the initial heap size.
-  expand(init_byte_size);
+  if (!expand(init_byte_size)) {
+    vm_exit_during_initialization("Failed to allocate initial heap.");
+    return JNI_ENOMEM;
+  }
 
   // Perform any initialization actions delegated to the policy.
   g1_policy()->init();
@@ -2744,7 +2782,7 @@
 }
 
 size_t G1CollectedHeap::max_capacity() const {
-  return g1_reserved_obj_bytes();
+  return _g1_reserved.byte_size();
 }
 
 jlong G1CollectedHeap::millis_since_last_gc() {
@@ -3538,7 +3576,12 @@
         size_t expand_bytes = g1_policy()->expansion_amount();
         if (expand_bytes > 0) {
           size_t bytes_before = capacity();
-          expand(expand_bytes);
+          if (!expand(expand_bytes)) {
+            // We failed to expand the heap so let's verify that
+            // committed/uncommitted amount match the backing store
+            assert(capacity() == _g1_storage.committed_size(), "committed size mismatch");
+            assert(max_capacity() == _g1_storage.reserved_size(), "reserved size mismatch");
+          }
         }
       }
 
@@ -3762,7 +3805,7 @@
 
     if (alloc_region == NULL) {
       // we will get a new GC alloc region
-      alloc_region = new_gc_alloc_region(ap, 0);
+      alloc_region = new_gc_alloc_region(ap, HeapRegion::GrainWords);
     } else {
       // the region was retained from the last collection
       ++_gc_alloc_region_counts[ap];
@@ -5311,7 +5354,7 @@
 
 size_t G1CollectedHeap::max_regions() {
   return
-    (size_t)align_size_up(g1_reserved_obj_bytes(), HeapRegion::GrainBytes) /
+    (size_t)align_size_up(max_capacity(), HeapRegion::GrainBytes) /
     HeapRegion::GrainBytes;
 }