RFR: 8059066: CardTableModRefBS might commit the same page twice
Erik Helin
erik.helin at oracle.com
Mon Oct 20 13:21:49 UTC 2014
Hi all,
this patch fixes an issue with overlapping commits in cardTableModRefBS.
If the JVM is started with the options
-Xmx8m -XX:-UseLargePages -version
on a system with a smallest page size of 8kB, then cardTableModRefBS
will commit the same page twice. Given how os::commit_memory works, the
issue is benign: mmap will simply overwrite the page with zeroes again,
and since this is during initialization, the card table is only filled
with zeroes. However, the issue becomes annoying when running with
-XX:NativeMemoryTracking=detail, since NMT will report the overlapping
commit.
The patch is a little tricky, since the surrounding code is a bit
intertwined. I will try to explain the patch step-by-step, it is
composed of two parts:
1. Update which committed regions we check when determining if
`new_end_aligned` interferes with another region.
2. Update the criteria for checking if `new_end_aligned` interferes with
another region.
The patch for the first part is:
--- a/src/share/vm/memory/cardTableModRefBS.cpp
+++ b/src/share/vm/memory/cardTableModRefBS.cpp
@@ -277,5 +277,5 @@ void CardTableModRefBS::resize_covered_r
// space of another region.
int ri = 0;
- for (ri = 0; ri < _cur_covered_regions; ri++) {
+ for (ri = ind + 1; ri < _cur_covered_regions; ri++) {
if (ri != ind) {
if (_committed[ri].contains(new_end_aligned)) {
We only need to check if `new_end_aligned` clashes with regions
following `ind`, since the code a few lines above handles regions before
`ind`:
265 HeapWord* const max_prev_end = largest_prev_committed_end(ind);
266 if (max_prev_end > cur_committed.end()) {
267 cur_committed.set_end(max_prev_end);
268 }
We only commit more memory if
`new_end_for_commit > cur_committed.end()` where
`new_end_for_commit` is equal to new_end_for_aligned`. Hence, the case
where a region before `ind` already have committed memory up to (or
beyond) `new_end_aligned` is taken care of. Therefore, we only need to
check regions after `ind`, which is the patch above. This is also
confirmed by an existing comment and assert in the loop body:
285 // Any region containing the new end
286 // should start at or beyond the region found (ind)
287 // for the new end (committed regions are not expected to
288 // be proper subsets of other committed regions).
289 assert(_committed[ri].start() >= _committed[ind].start(),
290 "New end of committed region is inconsistent");
Since the committed regions should be sorted according their start
address (see CardTableModRefBS::find_covering_region_by_base), the
assert can only fail for regions where `ri < ind`.
The second part of the patch then updates the criteria for determining
if `new_end_aligned` interferes with a region after `ind`:
--- a/src/share/vm/memory/cardTableModRefBS.cpp
+++ b/src/share/vm/memory/cardTableModRefBS.cpp
@@ -279,5 +279,6 @@ void CardTableModRefBS::resize_covered_r
for (ri = ind + 1; ri < _cur_covered_regions; ri++) {
if (ri != ind) {
- if (_committed[ri].contains(new_end_aligned)) {
+ if (new_end_aligned > _committed[ri].start() &&
+ new_end_aligned <= _committed[ri].end()) {
// The prior check included in the assert
// (new_end_aligned >= _committed[ri].start())
`_committed[ri].contains(new_end_aligned)` only checks:
bool contains(const void* addr) const {
return addr >= (void*)_start && addr < (void*)end();
}
and therefore misses the case when `new_end_aligned` completely covers
the region _committed[ri], that is,
`new_end_aligned == _committed[ri].end()`. This is fixed by the above patch.
Given the above two patches, the `if (ri != ind`)` check can be removed
from the loop body and the loop body can therefore remove two spaces of
indentation. I also removed an outdated comment.
Webrev:
http://cr.openjdk.java.net/~ehelin/8059066/webrev.00/
Bug:
https://bugs.openjdk.java.net/browse/JDK-8059066
Testing:
- JPRT
- Ad-hoc (Window 32/64, Linux 32/64, OS X 64, Solaris x86-64/SPARC):
- Dacapo, Kitchensink, Weblogic+medrec, runThese
- nsk.regression, vm.gc, vm.oom, vm.parallel_class_loading,
vm.regression, vm.runtime
- nashorn regression tests
- JTReg:
- HotSpot
- jdk_core, jdk_svc
- Running -Xmx8m -XX:-UseLargePages -version on a machine with 8kB pages
Thanks,
Erik
More information about the hotspot-gc-dev
mailing list