--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 05 21:02:05 2012 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 05 21:21:55 2012 -0800
@@ -591,17 +591,29 @@
}
res = new_region_try_secondary_free_list();
}
- if (res == NULL && do_expand) {
+ if (res == NULL && do_expand && _expand_heap_after_alloc_failure) {
+ // Currently, only attempts to allocate GC alloc regions set
+ // do_expand to true. So, we should only reach here during a
+ // safepoint. If this assumption changes we might have to
+ // reconsider the use of _expand_heap_after_alloc_failure.
+ assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+
ergo_verbose1(ErgoHeapSizing,
"attempt heap expansion",
ergo_format_reason("region allocation request failed")
ergo_format_byte("allocation request"),
word_size * HeapWordSize);
if (expand(word_size * HeapWordSize)) {
- // Even though the heap was expanded, it might not have reached
- // the desired size. So, we cannot assume that the allocation
- // will succeed.
+ // Given that expand() succeeded in expanding the heap, and we
+ // always expand the heap by an amount aligned to the heap
+ // region size, the free list should in theory not be empty. So
+ // it would probably be OK to use remove_head(). But the extra
+ // check for NULL is unlikely to be a performance issue here (we
+ // just expanded the heap!) so let's just be conservative and
+ // use remove_head_or_null().
res = _free_list.remove_head_or_null();
+ } else {
+ _expand_heap_after_alloc_failure = false;
}
}
return res;
@@ -1838,6 +1850,7 @@
_young_list(new YoungList(this)),
_gc_time_stamp(0),
_retained_old_gc_alloc_region(NULL),
+ _expand_heap_after_alloc_failure(true),
_surviving_young_words(NULL),
_full_collections_completed(0),
_in_cset_fast_test(NULL),
@@ -5439,6 +5452,7 @@
}
void G1CollectedHeap::evacuate_collection_set() {
+ _expand_heap_after_alloc_failure = true;
set_evacuation_failed(false);
g1_rem_set()->prepare_for_oops_into_collection_set_do();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 05 21:02:05 2012 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 05 21:21:55 2012 -0800
@@ -285,6 +285,14 @@
// Typically, it is not full so we should re-use it during the next GC.
HeapRegion* _retained_old_gc_alloc_region;
+ // It specifies whether we should attempt to expand the heap after a
+ // region allocation failure. If heap expansion fails we set this to
+ // false so that we don't re-attempt the heap expansion (it's likely
+ // that subsequent expansion attempts will also fail if one fails).
+ // Currently, it is only consulted during GC and it's reset at the
+ // start of each GC.
+ bool _expand_heap_after_alloc_failure;
+
// It resets the mutator alloc region before new allocations can take place.
void init_mutator_alloc_region();