提交 a2031db9 编写于 作者: J johnc

6923430: G1: assert(res != 0,"This should have worked.")

7007446: G1: expand the heap with a single step, not one region at a time
Summary: Changed G1CollectedHeap::expand() to expand the committed space by calling VirtualSpace::expand_by() once rather than for every region in the expansion amount. This allows the success or failure of the expansion to be determined before creating any heap regions. Introduced a develop flag G1ExitOnExpansionFailure (false by default) that, when true, will exit the VM if the expansion of the committed space fails. Finally G1CollectedHeap::expand() returns a status back to it's caller so that the caller knows whether to attempt the allocation.
Reviewed-by: brutisso, tonyp
上级 87c2c154
/* /*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -99,7 +99,7 @@ void ConcurrentG1Refine::init() { ...@@ -99,7 +99,7 @@ void ConcurrentG1Refine::init() {
if (G1ConcRSLogCacheSize > 0) { if (G1ConcRSLogCacheSize > 0) {
_g1h = G1CollectedHeap::heap(); _g1h = G1CollectedHeap::heap();
_max_n_card_counts = _max_n_card_counts =
(unsigned) (_g1h->g1_reserved_obj_bytes() >> CardTableModRefBS::card_shift); (unsigned) (_g1h->max_capacity() >> CardTableModRefBS::card_shift);
size_t max_card_num = ((size_t)1 << (sizeof(unsigned)*BitsPerByte-1)) - 1; size_t max_card_num = ((size_t)1 << (sizeof(unsigned)*BitsPerByte-1)) - 1;
guarantee(_max_n_card_counts < max_card_num, "card_num representation"); guarantee(_max_n_card_counts < max_card_num, "card_num representation");
......
...@@ -546,8 +546,11 @@ HeapRegion* G1CollectedHeap::new_region_work(size_t word_size, ...@@ -546,8 +546,11 @@ HeapRegion* G1CollectedHeap::new_region_work(size_t word_size,
res = new_region_try_secondary_free_list(word_size); res = new_region_try_secondary_free_list(word_size);
} }
if (res == NULL && do_expand) { if (res == NULL && do_expand) {
expand(word_size * HeapWordSize); if (expand(word_size * HeapWordSize)) {
res = _free_list.remove_head_or_null(); // 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 (res != NULL) {
if (G1PrintHeapRegions) { if (G1PrintHeapRegions) {
...@@ -631,9 +634,22 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { ...@@ -631,9 +634,22 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) {
if (first == -1) { if (first == -1) {
// The only thing we can do now is attempt expansion. // The only thing we can do now is attempt expansion.
if (fs + x_size >= num_regions) { if (fs + x_size >= num_regions) {
expand((num_regions - fs) * HeapRegion::GrainBytes); // If the number of regions we're trying to allocate for this
first = humongous_obj_allocate_find_first(num_regions, word_size); // object is at most the number of regions in the free suffix,
assert(first != -1, "this should have worked"); // 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 @@ resize_if_necessary_after_full_collection(size_t word_size) { ...@@ -1647,16 +1663,17 @@ resize_if_necessary_after_full_collection(size_t word_size) {
if (capacity_after_gc < minimum_desired_capacity) { if (capacity_after_gc < minimum_desired_capacity) {
// Don't expand unless it's significant // Don't expand unless it's significant
size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
expand(expand_bytes); if (expand(expand_bytes)) {
if (PrintGC && Verbose) { if (PrintGC && Verbose) {
gclog_or_tty->print_cr(" " gclog_or_tty->print_cr(" "
" expanding:" " expanding:"
" max_heap_size: %6.1fK" " max_heap_size: %6.1fK"
" minimum_desired_capacity: %6.1fK" " minimum_desired_capacity: %6.1fK"
" expand_bytes: %6.1fK", " expand_bytes: %6.1fK",
(double) max_heap_size / (double) K, (double) max_heap_size / (double) K,
(double) minimum_desired_capacity / (double) K, (double) minimum_desired_capacity / (double) K,
(double) expand_bytes / (double) K); (double) expand_bytes / (double) K);
}
} }
// No expansion, now see if we want to shrink // No expansion, now see if we want to shrink
...@@ -1757,66 +1774,84 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { ...@@ -1757,66 +1774,84 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) {
verify_region_sets_optional(); verify_region_sets_optional();
size_t expand_bytes = word_size * HeapWordSize; size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes);
if (expand_bytes < MinHeapDeltaBytes) { if (expand(expand_bytes)) {
expand_bytes = MinHeapDeltaBytes; verify_region_sets_optional();
return attempt_allocation_at_safepoint(word_size,
false /* expect_null_cur_alloc_region */);
} }
expand(expand_bytes); return NULL;
verify_region_sets_optional();
return attempt_allocation_at_safepoint(word_size,
false /* expect_null_cur_alloc_region */);
} }
// FIXME: both this and shrink could probably be more efficient by bool G1CollectedHeap::expand(size_t expand_bytes) {
// doing one "VirtualSpace::expand_by" call rather than several.
void G1CollectedHeap::expand(size_t expand_bytes) {
size_t old_mem_size = _g1_storage.committed_size(); size_t old_mem_size = _g1_storage.committed_size();
// We expand by a minimum of 1K. size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
expand_bytes = MAX2(expand_bytes, (size_t)K);
size_t aligned_expand_bytes =
ReservedSpace::page_align_size_up(expand_bytes);
aligned_expand_bytes = align_size_up(aligned_expand_bytes, aligned_expand_bytes = align_size_up(aligned_expand_bytes,
HeapRegion::GrainBytes); HeapRegion::GrainBytes);
expand_bytes = aligned_expand_bytes;
while (expand_bytes > 0) { if (Verbose && PrintGC) {
HeapWord* base = (HeapWord*)_g1_storage.high(); gclog_or_tty->print("Expanding garbage-first heap from %ldK by %ldK",
// Commit more storage. old_mem_size/K, aligned_expand_bytes/K);
bool successful = _g1_storage.expand_by(HeapRegion::GrainBytes); }
if (!successful) {
expand_bytes = 0; HeapWord* old_end = (HeapWord*)_g1_storage.high();
} else { bool successful = _g1_storage.expand_by(aligned_expand_bytes);
expand_bytes -= HeapRegion::GrainBytes; if (successful) {
// Expand the committed region. HeapWord* new_end = (HeapWord*)_g1_storage.high();
HeapWord* high = (HeapWord*) _g1_storage.high();
_g1_committed.set_end(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. // Create a new HeapRegion.
MemRegion mr(base, high); MemRegion mr(base, high);
bool is_zeroed = !_g1_max_committed.contains(base); bool is_zeroed = !_g1_max_committed.contains(base);
HeapRegion* hr = new HeapRegion(_bot_shared, mr, is_zeroed); 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. // Add it to the HeapRegionSeq.
_hrs->insert(hr); _hrs->insert(hr);
_free_list.add_as_tail(hr); _free_list.add_as_tail(hr);
// And we used up an expansion region to create it. // And we used up an expansion region to create it.
_expansion_regions--; _expansion_regions--;
// Tell the cardtable about it.
Universe::heap()->barrier_set()->resize_covered_region(_g1_committed); expand_bytes -= HeapRegion::GrainBytes;
// And the offset table as well. base += HeapRegion::GrainWords;
_bot_shared->resize(_g1_committed.word_size()); }
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) { if (Verbose && PrintGC) {
size_t new_mem_size = _g1_storage.committed_size(); size_t new_mem_size = _g1_storage.committed_size();
gclog_or_tty->print_cr("Expanding garbage-first heap from %ldK by %ldK to %ldK", gclog_or_tty->print_cr("...%s, expanded to %ldK",
old_mem_size/K, aligned_expand_bytes/K, (successful ? "Successful" : "Failed"),
new_mem_size/K); new_mem_size/K);
} }
return successful;
} }
void G1CollectedHeap::shrink_helper(size_t shrink_bytes) void G1CollectedHeap::shrink_helper(size_t shrink_bytes)
...@@ -2088,7 +2123,10 @@ jint G1CollectedHeap::initialize() { ...@@ -2088,7 +2123,10 @@ jint G1CollectedHeap::initialize() {
HeapRegionRemSet::init_heap(max_regions()); HeapRegionRemSet::init_heap(max_regions());
// Now expand into the initial heap size. // 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. // Perform any initialization actions delegated to the policy.
g1_policy()->init(); g1_policy()->init();
...@@ -2744,7 +2782,7 @@ size_t G1CollectedHeap::large_typearray_limit() { ...@@ -2744,7 +2782,7 @@ size_t G1CollectedHeap::large_typearray_limit() {
} }
size_t G1CollectedHeap::max_capacity() const { size_t G1CollectedHeap::max_capacity() const {
return g1_reserved_obj_bytes(); return _g1_reserved.byte_size();
} }
jlong G1CollectedHeap::millis_since_last_gc() { jlong G1CollectedHeap::millis_since_last_gc() {
...@@ -3538,7 +3576,12 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { ...@@ -3538,7 +3576,12 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
size_t expand_bytes = g1_policy()->expansion_amount(); size_t expand_bytes = g1_policy()->expansion_amount();
if (expand_bytes > 0) { if (expand_bytes > 0) {
size_t bytes_before = capacity(); 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 @@ void G1CollectedHeap::get_gc_alloc_regions() { ...@@ -3762,7 +3805,7 @@ void G1CollectedHeap::get_gc_alloc_regions() {
if (alloc_region == NULL) { if (alloc_region == NULL) {
// we will get a new GC alloc region // 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 { } else {
// the region was retained from the last collection // the region was retained from the last collection
++_gc_alloc_region_counts[ap]; ++_gc_alloc_region_counts[ap];
...@@ -5311,7 +5354,7 @@ size_t G1CollectedHeap::n_regions() { ...@@ -5311,7 +5354,7 @@ size_t G1CollectedHeap::n_regions() {
size_t G1CollectedHeap::max_regions() { size_t G1CollectedHeap::max_regions() {
return return
(size_t)align_size_up(g1_reserved_obj_bytes(), HeapRegion::GrainBytes) / (size_t)align_size_up(max_capacity(), HeapRegion::GrainBytes) /
HeapRegion::GrainBytes; HeapRegion::GrainBytes;
} }
......
...@@ -619,8 +619,10 @@ protected: ...@@ -619,8 +619,10 @@ protected:
public: public:
// Expand the garbage-first heap by at least the given size (in bytes!). // Expand the garbage-first heap by at least the given size (in bytes!).
// Returns true if the heap was expanded by the requested amount;
// false otherwise.
// (Rounds up to a HeapRegion boundary.) // (Rounds up to a HeapRegion boundary.)
virtual void expand(size_t expand_bytes); bool expand(size_t expand_bytes);
// Do anything common to GC's. // Do anything common to GC's.
virtual void gc_prologue(bool full); virtual void gc_prologue(bool full);
...@@ -981,9 +983,6 @@ public: ...@@ -981,9 +983,6 @@ public:
// Reference Processing accessor // Reference Processing accessor
ReferenceProcessor* ref_processor() { return _ref_processor; } ReferenceProcessor* ref_processor() { return _ref_processor; }
// Reserved (g1 only; super method includes perm), capacity and the used
// portion in bytes.
size_t g1_reserved_obj_bytes() const { return _g1_reserved.byte_size(); }
virtual size_t capacity() const; virtual size_t capacity() const;
virtual size_t used() const; virtual size_t used() const;
// This should be called when we're not holding the heap lock. The // This should be called when we're not holding the heap lock. The
......
...@@ -2011,7 +2011,7 @@ size_t G1CollectorPolicy::expansion_amount() { ...@@ -2011,7 +2011,7 @@ size_t G1CollectorPolicy::expansion_amount() {
// space, whichever is smaller, bounded below by a minimum // space, whichever is smaller, bounded below by a minimum
// expansion (unless that's all that's left.) // expansion (unless that's all that's left.)
const size_t min_expand_bytes = 1*M; const size_t min_expand_bytes = 1*M;
size_t reserved_bytes = _g1->g1_reserved_obj_bytes(); size_t reserved_bytes = _g1->max_capacity();
size_t committed_bytes = _g1->capacity(); size_t committed_bytes = _g1->capacity();
size_t uncommitted_bytes = reserved_bytes - committed_bytes; size_t uncommitted_bytes = reserved_bytes - committed_bytes;
size_t expand_bytes; size_t expand_bytes;
......
/* /*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -735,7 +735,7 @@ bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, ...@@ -735,7 +735,7 @@ bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
MemRegion dirtyRegion(start, end); MemRegion dirtyRegion(start, end);
#if CARD_REPEAT_HISTO #if CARD_REPEAT_HISTO
init_ct_freq_table(_g1->g1_reserved_obj_bytes()); init_ct_freq_table(_g1->max_capacity());
ct_freq_note_card(_ct_bs->index_for(start)); ct_freq_note_card(_ct_bs->index_for(start));
#endif #endif
......
...@@ -301,9 +301,13 @@ ...@@ -301,9 +301,13 @@
develop(uintx, G1StressConcRegionFreeingDelayMillis, 0, \ develop(uintx, G1StressConcRegionFreeingDelayMillis, 0, \
"Artificial delay during concurrent region freeing") \ "Artificial delay during concurrent region freeing") \
\ \
develop(bool, ReduceInitialCardMarksForG1, false, \ develop(bool, ReduceInitialCardMarksForG1, false, \
"When ReduceInitialCardMarks is true, this flag setting " \ "When ReduceInitialCardMarks is true, this flag setting " \
" controls whether G1 allows the RICM optimization") " controls whether G1 allows the RICM optimization") \
\
develop(bool, G1ExitOnExpansionFailure, false, \
"Raise a fatal VM exit out of memory failure in the event " \
" that heap expansion fails due to running out of swap.")
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册