src/share/vm/gc_implementation/g1/g1AllocRegion.cpp

Fri, 10 Oct 2014 15:51:58 +0200

author
tschatzl
date
Fri, 10 Oct 2014 15:51:58 +0200
changeset 7257
e7d0505c8a30
parent 7118
227a9e5e4b4a
child 7535
7ae4e26cb1e0
child 7651
c132be0fb74d
permissions
-rw-r--r--

8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso

tonyp@2715 1 /*
drchase@6680 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
tonyp@2715 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
tonyp@2715 4 *
tonyp@2715 5 * This code is free software; you can redistribute it and/or modify it
tonyp@2715 6 * under the terms of the GNU General Public License version 2 only, as
tonyp@2715 7 * published by the Free Software Foundation.
tonyp@2715 8 *
tonyp@2715 9 * This code is distributed in the hope that it will be useful, but WITHOUT
tonyp@2715 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
tonyp@2715 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
tonyp@2715 12 * version 2 for more details (a copy is included in the LICENSE file that
tonyp@2715 13 * accompanied this code).
tonyp@2715 14 *
tonyp@2715 15 * You should have received a copy of the GNU General Public License version
tonyp@2715 16 * 2 along with this work; if not, write to the Free Software Foundation,
tonyp@2715 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
tonyp@2715 18 *
tonyp@2715 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
tonyp@2715 20 * or visit www.oracle.com if you need additional information or have any
tonyp@2715 21 * questions.
tonyp@2715 22 *
tonyp@2715 23 */
tonyp@2715 24
tonyp@2715 25 #include "precompiled.hpp"
tonyp@2715 26 #include "gc_implementation/g1/g1AllocRegion.inline.hpp"
tonyp@2715 27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
goetz@6911 28 #include "runtime/orderAccess.inline.hpp"
tonyp@2715 29
tonyp@2715 30 G1CollectedHeap* G1AllocRegion::_g1h = NULL;
tonyp@2715 31 HeapRegion* G1AllocRegion::_dummy_region = NULL;
tonyp@2715 32
tonyp@2715 33 void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) {
tonyp@2715 34 assert(_dummy_region == NULL, "should be set once");
tonyp@2715 35 assert(dummy_region != NULL, "pre-condition");
tonyp@2715 36 assert(dummy_region->free() == 0, "pre-condition");
tonyp@2715 37
tonyp@2715 38 // Make sure that any allocation attempt on this region will fail
tonyp@2715 39 // and will not trigger any asserts.
tonyp@2715 40 assert(allocate(dummy_region, 1, false) == NULL, "should fail");
tonyp@2715 41 assert(par_allocate(dummy_region, 1, false) == NULL, "should fail");
tonyp@2715 42 assert(allocate(dummy_region, 1, true) == NULL, "should fail");
tonyp@2715 43 assert(par_allocate(dummy_region, 1, true) == NULL, "should fail");
tonyp@2715 44
tonyp@2715 45 _g1h = g1h;
tonyp@2715 46 _dummy_region = dummy_region;
tonyp@2715 47 }
tonyp@2715 48
tonyp@2715 49 void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
tonyp@2715 50 bool bot_updates) {
tonyp@2715 51 assert(alloc_region != NULL && alloc_region != _dummy_region,
tonyp@2715 52 "pre-condition");
tonyp@2715 53
tonyp@2715 54 // Other threads might still be trying to allocate using a CAS out
tonyp@2715 55 // of the region we are trying to retire, as they can do so without
tonyp@2715 56 // holding the lock. So, we first have to make sure that noone else
tonyp@2715 57 // can allocate out of it by doing a maximal allocation. Even if our
tonyp@2715 58 // CAS attempt fails a few times, we'll succeed sooner or later
tonyp@2715 59 // given that failed CAS attempts mean that the region is getting
tonyp@2715 60 // closed to being full.
tonyp@2715 61 size_t free_word_size = alloc_region->free() / HeapWordSize;
tonyp@2715 62
tonyp@2715 63 // This is the minimum free chunk we can turn into a dummy
tonyp@2715 64 // object. If the free space falls below this, then noone can
tonyp@2715 65 // allocate in this region anyway (all allocation requests will be
tonyp@2715 66 // of a size larger than this) so we won't have to perform the dummy
tonyp@2715 67 // allocation.
tonyp@2715 68 size_t min_word_size_to_fill = CollectedHeap::min_fill_size();
tonyp@2715 69
tonyp@2715 70 while (free_word_size >= min_word_size_to_fill) {
tonyp@2715 71 HeapWord* dummy = par_allocate(alloc_region, free_word_size, bot_updates);
tonyp@2715 72 if (dummy != NULL) {
tonyp@2715 73 // If the allocation was successful we should fill in the space.
tonyp@2715 74 CollectedHeap::fill_with_object(dummy, free_word_size);
tonyp@2715 75 alloc_region->set_pre_dummy_top(dummy);
tonyp@2715 76 break;
tonyp@2715 77 }
tonyp@2715 78
tonyp@2715 79 free_word_size = alloc_region->free() / HeapWordSize;
tonyp@2715 80 // It's also possible that someone else beats us to the
tonyp@2715 81 // allocation and they fill up the region. In that case, we can
tonyp@2715 82 // just get out of the loop.
tonyp@2715 83 }
tonyp@2715 84 assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill,
tonyp@2715 85 "post-condition");
tonyp@2715 86 }
tonyp@2715 87
tonyp@2715 88 void G1AllocRegion::retire(bool fill_up) {
tonyp@2715 89 assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
tonyp@2715 90
tonyp@2715 91 trace("retiring");
tonyp@2715 92 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 93 if (alloc_region != _dummy_region) {
tonyp@2715 94 // We never have to check whether the active region is empty or not,
tonyp@2715 95 // and potentially free it if it is, given that it's guaranteed that
tonyp@2715 96 // it will never be empty.
tonyp@2715 97 assert(!alloc_region->is_empty(),
tonyp@2715 98 ar_ext_msg(this, "the alloc region should never be empty"));
tonyp@2715 99
tonyp@2715 100 if (fill_up) {
tonyp@2715 101 fill_up_remaining_space(alloc_region, _bot_updates);
tonyp@2715 102 }
tonyp@2715 103
tonyp@2715 104 assert(alloc_region->used() >= _used_bytes_before,
tonyp@2715 105 ar_ext_msg(this, "invariant"));
tonyp@2715 106 size_t allocated_bytes = alloc_region->used() - _used_bytes_before;
tonyp@2715 107 retire_region(alloc_region, allocated_bytes);
tonyp@2715 108 _used_bytes_before = 0;
tonyp@2715 109 _alloc_region = _dummy_region;
tonyp@2715 110 }
tonyp@2715 111 trace("retired");
tonyp@2715 112 }
tonyp@2715 113
tonyp@2715 114 HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
tonyp@2715 115 bool force) {
tonyp@2715 116 assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition"));
tonyp@2715 117 assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition"));
tonyp@2715 118
tonyp@2715 119 trace("attempting region allocation");
tonyp@2715 120 HeapRegion* new_alloc_region = allocate_new_region(word_size, force);
tonyp@2715 121 if (new_alloc_region != NULL) {
tonyp@2715 122 new_alloc_region->reset_pre_dummy_top();
tonyp@2715 123 // Need to do this before the allocation
tonyp@2715 124 _used_bytes_before = new_alloc_region->used();
tonyp@2715 125 HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates);
tonyp@2715 126 assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded"));
tonyp@2715 127
tonyp@2715 128 OrderAccess::storestore();
tonyp@2715 129 // Note that we first perform the allocation and then we store the
tonyp@2715 130 // region in _alloc_region. This is the reason why an active region
tonyp@2715 131 // can never be empty.
sjohanss@7118 132 update_alloc_region(new_alloc_region);
tonyp@2715 133 trace("region allocation successful");
tonyp@2715 134 return result;
tonyp@2715 135 } else {
tonyp@2715 136 trace("region allocation failed");
tonyp@2715 137 return NULL;
tonyp@2715 138 }
tonyp@2715 139 ShouldNotReachHere();
tonyp@2715 140 }
tonyp@2715 141
tonyp@2715 142 void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) {
tonyp@3713 143 msg->append("[%s] %s c: %u b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT,
tonyp@3028 144 _name, message, _count, BOOL_TO_STR(_bot_updates),
drchase@6680 145 p2i(_alloc_region), _used_bytes_before);
tonyp@2715 146 }
tonyp@2715 147
tonyp@2715 148 void G1AllocRegion::init() {
tonyp@2715 149 trace("initializing");
tonyp@2715 150 assert(_alloc_region == NULL && _used_bytes_before == 0,
tonyp@2715 151 ar_ext_msg(this, "pre-condition"));
tonyp@3028 152 assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set"));
tonyp@2715 153 _alloc_region = _dummy_region;
tonyp@3028 154 _count = 0;
tonyp@2715 155 trace("initialized");
tonyp@2715 156 }
tonyp@2715 157
tonyp@3028 158 void G1AllocRegion::set(HeapRegion* alloc_region) {
tonyp@3028 159 trace("setting");
tonyp@3028 160 // We explicitly check that the region is not empty to make sure we
tonyp@3028 161 // maintain the "the alloc region cannot be empty" invariant.
tonyp@3028 162 assert(alloc_region != NULL && !alloc_region->is_empty(),
tonyp@3028 163 ar_ext_msg(this, "pre-condition"));
tonyp@3028 164 assert(_alloc_region == _dummy_region &&
tonyp@3028 165 _used_bytes_before == 0 && _count == 0,
tonyp@3028 166 ar_ext_msg(this, "pre-condition"));
tonyp@3028 167
tonyp@3028 168 _used_bytes_before = alloc_region->used();
tonyp@3028 169 _alloc_region = alloc_region;
tonyp@3028 170 _count += 1;
tonyp@3028 171 trace("set");
tonyp@3028 172 }
tonyp@3028 173
sjohanss@7118 174 void G1AllocRegion::update_alloc_region(HeapRegion* alloc_region) {
sjohanss@7118 175 trace("update");
sjohanss@7118 176 // We explicitly check that the region is not empty to make sure we
sjohanss@7118 177 // maintain the "the alloc region cannot be empty" invariant.
sjohanss@7118 178 assert(alloc_region != NULL && !alloc_region->is_empty(),
sjohanss@7118 179 ar_ext_msg(this, "pre-condition"));
sjohanss@7118 180
sjohanss@7118 181 _alloc_region = alloc_region;
sjohanss@7118 182 _alloc_region->set_allocation_context(allocation_context());
sjohanss@7118 183 _count += 1;
sjohanss@7118 184 trace("updated");
sjohanss@7118 185 }
sjohanss@7118 186
tonyp@2715 187 HeapRegion* G1AllocRegion::release() {
tonyp@2715 188 trace("releasing");
tonyp@2715 189 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 190 retire(false /* fill_up */);
tonyp@3028 191 assert(_alloc_region == _dummy_region,
tonyp@3028 192 ar_ext_msg(this, "post-condition of retire()"));
tonyp@2715 193 _alloc_region = NULL;
tonyp@2715 194 trace("released");
tonyp@2715 195 return (alloc_region == _dummy_region) ? NULL : alloc_region;
tonyp@2715 196 }
tonyp@2715 197
tonyp@2715 198 #if G1_ALLOC_REGION_TRACING
tonyp@2715 199 void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) {
tonyp@2715 200 // All the calls to trace that set either just the size or the size
tonyp@2715 201 // and the result are considered part of level 2 tracing and are
tonyp@2715 202 // skipped during level 1 tracing.
tonyp@2715 203 if ((word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) {
tonyp@2715 204 const size_t buffer_length = 128;
tonyp@2715 205 char hr_buffer[buffer_length];
tonyp@2715 206 char rest_buffer[buffer_length];
tonyp@2715 207
tonyp@2715 208 HeapRegion* alloc_region = _alloc_region;
tonyp@2715 209 if (alloc_region == NULL) {
tonyp@2715 210 jio_snprintf(hr_buffer, buffer_length, "NULL");
tonyp@2715 211 } else if (alloc_region == _dummy_region) {
tonyp@2715 212 jio_snprintf(hr_buffer, buffer_length, "DUMMY");
tonyp@2715 213 } else {
tonyp@2715 214 jio_snprintf(hr_buffer, buffer_length,
tonyp@2715 215 HR_FORMAT, HR_FORMAT_PARAMS(alloc_region));
tonyp@2715 216 }
tonyp@2715 217
tonyp@2715 218 if (G1_ALLOC_REGION_TRACING > 1) {
tonyp@2715 219 if (result != NULL) {
tonyp@2715 220 jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT" "PTR_FORMAT,
tonyp@2715 221 word_size, result);
tonyp@2715 222 } else if (word_size != 0) {
tonyp@2715 223 jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size);
tonyp@2715 224 } else {
tonyp@2715 225 jio_snprintf(rest_buffer, buffer_length, "");
tonyp@2715 226 }
tonyp@2715 227 } else {
tonyp@2715 228 jio_snprintf(rest_buffer, buffer_length, "");
tonyp@2715 229 }
tonyp@2715 230
tonyp@3713 231 tty->print_cr("[%s] %u %s : %s %s",
tonyp@3028 232 _name, _count, hr_buffer, str, rest_buffer);
tonyp@2715 233 }
tonyp@2715 234 }
tonyp@2715 235 #endif // G1_ALLOC_REGION_TRACING
tonyp@2715 236
tonyp@2715 237 G1AllocRegion::G1AllocRegion(const char* name,
tonyp@2715 238 bool bot_updates)
tonyp@2715 239 : _name(name), _bot_updates(bot_updates),
sjohanss@7118 240 _alloc_region(NULL), _count(0), _used_bytes_before(0),
sjohanss@7118 241 _allocation_context(AllocationContext::system()) { }
tonyp@2715 242
sjohanss@7118 243
sjohanss@7118 244 HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size,
sjohanss@7118 245 bool force) {
sjohanss@7118 246 return _g1h->new_mutator_alloc_region(word_size, force);
sjohanss@7118 247 }
sjohanss@7118 248
sjohanss@7118 249 void MutatorAllocRegion::retire_region(HeapRegion* alloc_region,
sjohanss@7118 250 size_t allocated_bytes) {
sjohanss@7118 251 _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes);
sjohanss@7118 252 }
sjohanss@7118 253
sjohanss@7118 254 HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size,
sjohanss@7118 255 bool force) {
sjohanss@7118 256 assert(!force, "not supported for GC alloc regions");
sjohanss@7118 257 return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForSurvived);
sjohanss@7118 258 }
sjohanss@7118 259
sjohanss@7118 260 void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region,
sjohanss@7118 261 size_t allocated_bytes) {
sjohanss@7118 262 _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes,
sjohanss@7118 263 GCAllocForSurvived);
sjohanss@7118 264 }
sjohanss@7118 265
sjohanss@7118 266 HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size,
sjohanss@7118 267 bool force) {
sjohanss@7118 268 assert(!force, "not supported for GC alloc regions");
sjohanss@7118 269 return _g1h->new_gc_alloc_region(word_size, count(), GCAllocForTenured);
sjohanss@7118 270 }
sjohanss@7118 271
sjohanss@7118 272 void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
sjohanss@7118 273 size_t allocated_bytes) {
sjohanss@7118 274 _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes,
sjohanss@7118 275 GCAllocForTenured);
sjohanss@7118 276 }
sjohanss@7118 277
sjohanss@7118 278 HeapRegion* OldGCAllocRegion::release() {
sjohanss@7118 279 HeapRegion* cur = get();
sjohanss@7118 280 if (cur != NULL) {
sjohanss@7118 281 // Determine how far we are from the next card boundary. If it is smaller than
sjohanss@7118 282 // the minimum object size we can allocate into, expand into the next card.
sjohanss@7118 283 HeapWord* top = cur->top();
sjohanss@7118 284 HeapWord* aligned_top = (HeapWord*)align_ptr_up(top, G1BlockOffsetSharedArray::N_bytes);
sjohanss@7118 285
sjohanss@7118 286 size_t to_allocate_words = pointer_delta(aligned_top, top, HeapWordSize);
sjohanss@7118 287
sjohanss@7118 288 if (to_allocate_words != 0) {
sjohanss@7118 289 // We are not at a card boundary. Fill up, possibly into the next, taking the
sjohanss@7118 290 // end of the region and the minimum object size into account.
sjohanss@7118 291 to_allocate_words = MIN2(pointer_delta(cur->end(), cur->top(), HeapWordSize),
sjohanss@7118 292 MAX2(to_allocate_words, G1CollectedHeap::min_fill_size()));
sjohanss@7118 293
sjohanss@7118 294 // Skip allocation if there is not enough space to allocate even the smallest
sjohanss@7118 295 // possible object. In this case this region will not be retained, so the
sjohanss@7118 296 // original problem cannot occur.
sjohanss@7118 297 if (to_allocate_words >= G1CollectedHeap::min_fill_size()) {
sjohanss@7118 298 HeapWord* dummy = attempt_allocation(to_allocate_words, true /* bot_updates */);
sjohanss@7118 299 CollectedHeap::fill_with_object(dummy, to_allocate_words);
sjohanss@7118 300 }
sjohanss@7118 301 }
sjohanss@7118 302 }
sjohanss@7118 303 return G1AllocRegion::release();
sjohanss@7118 304 }
sjohanss@7118 305
sjohanss@7118 306

mercurial