6952853: SIGSEGV with UseAdaptiveGCBoundary on 64b linux running jvm2008
Summary: Shrinking of a generation and the corresponding card table was causing part of the card table to be uncommitted.
Reviewed-by: jcoomes
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu Jun 10 08:27:35 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jun 23 08:35:31 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -566,14 +566,14 @@
#endif
// Commit new or uncommit old pages, if necessary.
- resize_commit_uncommit(changed_region, new_region);
+ if (resize_commit_uncommit(changed_region, new_region)) {
+ // Set the new start of the committed region
+ resize_update_committed_table(changed_region, new_region);
+ }
// Update card table entries
resize_update_card_table_entries(changed_region, new_region);
- // Set the new start of the committed region
- resize_update_committed_table(changed_region, new_region);
-
// Update the covered region
resize_update_covered_table(changed_region, new_region);
@@ -604,8 +604,9 @@
debug_only(verify_guard();)
}
-void CardTableExtension::resize_commit_uncommit(int changed_region,
+bool CardTableExtension::resize_commit_uncommit(int changed_region,
MemRegion new_region) {
+ bool result = false;
// Commit new or uncommit old pages, if necessary.
MemRegion cur_committed = _committed[changed_region];
assert(_covered[changed_region].end() == new_region.end(),
@@ -675,20 +676,31 @@
"card table expansion");
}
}
+ result = true;
} else if (new_start_aligned > cur_committed.start()) {
// Shrink the committed region
+#if 0 // uncommitting space is currently unsafe because of the interactions
+ // of growing and shrinking regions. One region A can uncommit space
+ // that it owns but which is being used by another region B (maybe).
+ // Region B has not committed the space because it was already
+ // committed by region A.
MemRegion uncommit_region = committed_unique_to_self(changed_region,
MemRegion(cur_committed.start(), new_start_aligned));
if (!uncommit_region.is_empty()) {
if (!os::uncommit_memory((char*)uncommit_region.start(),
uncommit_region.byte_size())) {
- vm_exit_out_of_memory(uncommit_region.byte_size(),
- "card table contraction");
+ // If the uncommit fails, ignore it. Let the
+ // committed table resizing go even though the committed
+ // table will over state the committed space.
}
}
+#else
+ assert(!result, "Should be false with current workaround");
+#endif
}
assert(_committed[changed_region].end() == cur_committed.end(),
"end should not change");
+ return result;
}
void CardTableExtension::resize_update_committed_table(int changed_region,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Thu Jun 10 08:27:35 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.hpp Wed Jun 23 08:35:31 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,9 @@
class CardTableExtension : public CardTableModRefBS {
private:
// Support methods for resizing the card table.
- void resize_commit_uncommit(int changed_region, MemRegion new_region);
+ // resize_commit_uncommit() returns true if the pages were committed or
+ // uncommitted
+ bool resize_commit_uncommit(int changed_region, MemRegion new_region);
void resize_update_card_table_entries(int changed_region,
MemRegion new_region);
void resize_update_committed_table(int changed_region, MemRegion new_region);
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu Jun 10 08:27:35 2010 -0700
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Wed Jun 23 08:35:31 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -284,12 +284,19 @@
committed_unique_to_self(ind, MemRegion(new_end_aligned,
cur_committed.end()));
if (!uncommit_region.is_empty()) {
- if (!os::uncommit_memory((char*)uncommit_region.start(),
- uncommit_region.byte_size())) {
- assert(false, "Card table contraction failed");
- // The call failed so don't change the end of the
- // committed region. This is better than taking the
- // VM down.
+ // It is not safe to uncommit cards if the boundary between
+ // the generations is moving. A shrink can uncommit cards
+ // owned by generation A but being used by generation B.
+ if (!UseAdaptiveGCBoundary) {
+ if (!os::uncommit_memory((char*)uncommit_region.start(),
+ uncommit_region.byte_size())) {
+ assert(false, "Card table contraction failed");
+ // The call failed so don't change the end of the
+ // committed region. This is better than taking the
+ // VM down.
+ new_end_aligned = _committed[ind].end();
+ }
+ } else {
new_end_aligned = _committed[ind].end();
}
}
@@ -297,6 +304,19 @@
// In any case, we can reset the end of the current committed entry.
_committed[ind].set_end(new_end_aligned);
+#ifdef ASSERT
+ // Check that the last card in the new region is committed according
+ // to the tables.
+ bool covered = false;
+ for (int cr = 0; cr < _cur_covered_regions; cr++) {
+ if (_committed[cr].contains(new_end - 1)) {
+ covered = true;
+ break;
+ }
+ }
+ assert(covered, "Card for end of new region not committed");
+#endif
+
// The default of 0 is not necessarily clean cards.
jbyte* entry;
if (old_region.last() < _whole_heap.start()) {
@@ -354,6 +374,9 @@
addr_for((jbyte*) _committed[ind].start()),
addr_for((jbyte*) _committed[ind].last()));
}
+ // Touch the last card of the covered region to show that it
+ // is committed (or SEGV).
+ debug_only(*byte_for(_covered[ind].last());)
debug_only(verify_guard();)
}