# HG changeset patch # User jmasa # Date 1325827315 28800 # Node ID 5fd354a959c5e431e14c68632fecf3c906b4c09c # Parent 2ee4167627a35fc7e61da90a4713d5fab3511a5f# Parent bacb651cf5bfca4ac20d255c4ac9eb6e2bbda67f Merge diff -r 2ee4167627a3 -r 5fd354a959c5 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 05 21:02:05 2012 -0800 +++ b/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(); diff -r 2ee4167627a3 -r 5fd354a959c5 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 05 21:02:05 2012 -0800 +++ b/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();