diff -r 0edfdab48098 -r 65eafe3fb3c7 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- 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; }