Thu, 21 Aug 2014 16:44:41 +0200
8055098: WB API should be extended to provide information about size and age of object.
Summary: Extend the WhiteBox API to provide information about the size and age of objects. Further add a mechanism to trigger a young GC.
Reviewed-by: tschatzl, sjohanss
Contributed-by: Leonid Mesnik <leonid.mesnik@oracle.com>
ysr@777 | 1 | /* |
drchase@6680 | 2 | * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. |
ysr@777 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ysr@777 | 4 | * |
ysr@777 | 5 | * This code is free software; you can redistribute it and/or modify it |
ysr@777 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ysr@777 | 7 | * published by the Free Software Foundation. |
ysr@777 | 8 | * |
ysr@777 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ysr@777 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ysr@777 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ysr@777 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
ysr@777 | 13 | * accompanied this code). |
ysr@777 | 14 | * |
ysr@777 | 15 | * You should have received a copy of the GNU General Public License version |
ysr@777 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
ysr@777 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ysr@777 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
ysr@777 | 22 | * |
ysr@777 | 23 | */ |
ysr@777 | 24 | |
stefank@2314 | 25 | #include "precompiled.hpp" |
tonyp@2963 | 26 | #include "gc_implementation/g1/heapRegion.hpp" |
tonyp@2963 | 27 | #include "gc_implementation/g1/heapRegionSeq.inline.hpp" |
tschatzl@7050 | 28 | #include "gc_implementation/g1/heapRegionSet.inline.hpp" |
stefank@2314 | 29 | #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" |
tschatzl@7050 | 30 | #include "gc_implementation/g1/concurrentG1Refine.hpp" |
stefank@2314 | 31 | #include "memory/allocation.hpp" |
ysr@777 | 32 | |
tschatzl@7051 | 33 | void HeapRegionSeq::initialize(G1RegionToSpaceMapper* heap_storage, |
tschatzl@7051 | 34 | G1RegionToSpaceMapper* prev_bitmap, |
tschatzl@7051 | 35 | G1RegionToSpaceMapper* next_bitmap, |
tschatzl@7051 | 36 | G1RegionToSpaceMapper* bot, |
tschatzl@7051 | 37 | G1RegionToSpaceMapper* cardtable, |
tschatzl@7051 | 38 | G1RegionToSpaceMapper* card_counts) { |
tschatzl@7050 | 39 | _allocated_heapregions_length = 0; |
tschatzl@7050 | 40 | |
tschatzl@7051 | 41 | _heap_mapper = heap_storage; |
tschatzl@7051 | 42 | |
tschatzl@7051 | 43 | _prev_bitmap_mapper = prev_bitmap; |
tschatzl@7051 | 44 | _next_bitmap_mapper = next_bitmap; |
tschatzl@7051 | 45 | |
tschatzl@7051 | 46 | _bot_mapper = bot; |
tschatzl@7051 | 47 | _cardtable_mapper = cardtable; |
tschatzl@7051 | 48 | |
tschatzl@7051 | 49 | _card_counts_mapper = card_counts; |
tschatzl@7051 | 50 | |
tschatzl@7051 | 51 | MemRegion reserved = heap_storage->reserved(); |
tschatzl@7051 | 52 | _regions.initialize(reserved.start(), reserved.end(), HeapRegion::GrainBytes); |
tschatzl@7051 | 53 | |
tschatzl@7051 | 54 | _available_map.resize(_regions.length(), false); |
tschatzl@7051 | 55 | _available_map.clear(); |
tschatzl@7050 | 56 | } |
tschatzl@7050 | 57 | |
tschatzl@7050 | 58 | bool HeapRegionSeq::is_available(uint region) const { |
tschatzl@7051 | 59 | return _available_map.at(region); |
tschatzl@7050 | 60 | } |
tschatzl@7050 | 61 | |
tschatzl@7050 | 62 | #ifdef ASSERT |
tschatzl@7050 | 63 | bool HeapRegionSeq::is_free(HeapRegion* hr) const { |
tschatzl@7050 | 64 | return _free_list.contains(hr); |
tschatzl@7050 | 65 | } |
tschatzl@7050 | 66 | #endif |
tschatzl@7050 | 67 | |
tschatzl@7050 | 68 | HeapRegion* HeapRegionSeq::new_heap_region(uint hrs_index) { |
tschatzl@7050 | 69 | HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrs_index); |
tschatzl@7050 | 70 | MemRegion mr(bottom, bottom + HeapRegion::GrainWords); |
tschatzl@7050 | 71 | assert(reserved().contains(mr), "invariant"); |
tschatzl@7050 | 72 | return new HeapRegion(hrs_index, G1CollectedHeap::heap()->bot_shared(), mr); |
tschatzl@7050 | 73 | } |
tschatzl@7050 | 74 | |
tschatzl@7050 | 75 | void HeapRegionSeq::commit_regions(uint index, size_t num_regions) { |
tschatzl@7050 | 76 | guarantee(num_regions > 0, "Must commit more than zero regions"); |
tschatzl@7050 | 77 | guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions"); |
tschatzl@7050 | 78 | |
tschatzl@7051 | 79 | _num_committed += (uint)num_regions; |
tschatzl@7051 | 80 | |
tschatzl@7051 | 81 | _heap_mapper->commit_regions(index, num_regions); |
tschatzl@7051 | 82 | |
tschatzl@7051 | 83 | // Also commit auxiliary data |
tschatzl@7051 | 84 | _prev_bitmap_mapper->commit_regions(index, num_regions); |
tschatzl@7051 | 85 | _next_bitmap_mapper->commit_regions(index, num_regions); |
tschatzl@7051 | 86 | |
tschatzl@7051 | 87 | _bot_mapper->commit_regions(index, num_regions); |
tschatzl@7051 | 88 | _cardtable_mapper->commit_regions(index, num_regions); |
tschatzl@7051 | 89 | |
tschatzl@7051 | 90 | _card_counts_mapper->commit_regions(index, num_regions); |
tschatzl@7050 | 91 | } |
tschatzl@7050 | 92 | |
tschatzl@7050 | 93 | void HeapRegionSeq::uncommit_regions(uint start, size_t num_regions) { |
tschatzl@7051 | 94 | guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start)); |
tschatzl@7050 | 95 | guarantee(_num_committed >= num_regions, "pre-condition"); |
tschatzl@7050 | 96 | |
tschatzl@7050 | 97 | // Print before uncommitting. |
tschatzl@7050 | 98 | if (G1CollectedHeap::heap()->hr_printer()->is_active()) { |
tschatzl@7050 | 99 | for (uint i = start; i < start + num_regions; i++) { |
tschatzl@7050 | 100 | HeapRegion* hr = at(i); |
tschatzl@7050 | 101 | G1CollectedHeap::heap()->hr_printer()->uncommit(hr->bottom(), hr->end()); |
tonyp@2472 | 102 | } |
tonyp@2472 | 103 | } |
tschatzl@7050 | 104 | |
tschatzl@7050 | 105 | _num_committed -= (uint)num_regions; |
tschatzl@7050 | 106 | |
tschatzl@7051 | 107 | _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range); |
tschatzl@7051 | 108 | _heap_mapper->uncommit_regions(start, num_regions); |
tschatzl@7051 | 109 | |
tschatzl@7051 | 110 | // Also uncommit auxiliary data |
tschatzl@7051 | 111 | _prev_bitmap_mapper->uncommit_regions(start, num_regions); |
tschatzl@7051 | 112 | _next_bitmap_mapper->uncommit_regions(start, num_regions); |
tschatzl@7051 | 113 | |
tschatzl@7051 | 114 | _bot_mapper->uncommit_regions(start, num_regions); |
tschatzl@7051 | 115 | _cardtable_mapper->uncommit_regions(start, num_regions); |
tschatzl@7051 | 116 | |
tschatzl@7051 | 117 | _card_counts_mapper->uncommit_regions(start, num_regions); |
tschatzl@7050 | 118 | } |
tschatzl@7050 | 119 | |
tschatzl@7050 | 120 | void HeapRegionSeq::make_regions_available(uint start, uint num_regions) { |
tschatzl@7050 | 121 | guarantee(num_regions > 0, "No point in calling this for zero regions"); |
tschatzl@7050 | 122 | commit_regions(start, num_regions); |
tschatzl@7050 | 123 | for (uint i = start; i < start + num_regions; i++) { |
tschatzl@7050 | 124 | if (_regions.get_by_index(i) == NULL) { |
tschatzl@7050 | 125 | HeapRegion* new_hr = new_heap_region(i); |
tschatzl@7050 | 126 | _regions.set_by_index(i, new_hr); |
tschatzl@7050 | 127 | _allocated_heapregions_length = MAX2(_allocated_heapregions_length, i + 1); |
tonyp@2472 | 128 | } |
tschatzl@7050 | 129 | } |
tschatzl@7050 | 130 | |
tschatzl@7051 | 131 | _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range); |
tschatzl@7050 | 132 | |
tschatzl@7050 | 133 | for (uint i = start; i < start + num_regions; i++) { |
tschatzl@7050 | 134 | assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i)); |
tschatzl@7050 | 135 | HeapRegion* hr = at(i); |
tschatzl@7050 | 136 | if (G1CollectedHeap::heap()->hr_printer()->is_active()) { |
tschatzl@7050 | 137 | G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end()); |
tschatzl@7050 | 138 | } |
tschatzl@7050 | 139 | HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(i); |
tschatzl@7050 | 140 | MemRegion mr(bottom, bottom + HeapRegion::GrainWords); |
tschatzl@7050 | 141 | |
tschatzl@7050 | 142 | hr->initialize(mr); |
tschatzl@7050 | 143 | insert_into_free_list(at(i)); |
tonyp@2472 | 144 | } |
tonyp@2472 | 145 | } |
tonyp@2472 | 146 | |
tschatzl@7050 | 147 | uint HeapRegionSeq::expand_by(uint num_regions) { |
tschatzl@7051 | 148 | return expand_at(0, num_regions); |
tonyp@2963 | 149 | } |
tonyp@2963 | 150 | |
tschatzl@7050 | 151 | uint HeapRegionSeq::expand_at(uint start, uint num_regions) { |
tschatzl@7050 | 152 | if (num_regions == 0) { |
tschatzl@7050 | 153 | return 0; |
tschatzl@7050 | 154 | } |
tonyp@2963 | 155 | |
tschatzl@7050 | 156 | uint cur = start; |
tschatzl@7050 | 157 | uint idx_last_found = 0; |
tschatzl@7050 | 158 | uint num_last_found = 0; |
tonyp@2963 | 159 | |
tschatzl@7050 | 160 | uint expanded = 0; |
tonyp@2963 | 161 | |
tschatzl@7050 | 162 | while (expanded < num_regions && |
tschatzl@7050 | 163 | (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) { |
tschatzl@7050 | 164 | uint to_expand = MIN2(num_regions - expanded, num_last_found); |
tschatzl@7050 | 165 | make_regions_available(idx_last_found, to_expand); |
tschatzl@7050 | 166 | expanded += to_expand; |
tschatzl@7050 | 167 | cur = idx_last_found + num_last_found + 1; |
tschatzl@7050 | 168 | } |
tonyp@2963 | 169 | |
tschatzl@7050 | 170 | verify_optional(); |
tschatzl@7050 | 171 | return expanded; |
tonyp@2963 | 172 | } |
tonyp@2963 | 173 | |
tschatzl@7050 | 174 | uint HeapRegionSeq::find_contiguous(size_t num, bool empty_only) { |
tschatzl@7050 | 175 | uint found = 0; |
tschatzl@7050 | 176 | size_t length_found = 0; |
tschatzl@7050 | 177 | uint cur = 0; |
tschatzl@7050 | 178 | |
tschatzl@7050 | 179 | while (length_found < num && cur < max_length()) { |
tschatzl@7050 | 180 | HeapRegion* hr = _regions.get_by_index(cur); |
tschatzl@7050 | 181 | if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) { |
tschatzl@7050 | 182 | // This region is a potential candidate for allocation into. |
tschatzl@7050 | 183 | length_found++; |
tschatzl@7050 | 184 | } else { |
tschatzl@7050 | 185 | // This region is not a candidate. The next region is the next possible one. |
tschatzl@7050 | 186 | found = cur + 1; |
tschatzl@7050 | 187 | length_found = 0; |
tonyp@2963 | 188 | } |
tschatzl@7050 | 189 | cur++; |
tonyp@2472 | 190 | } |
tschatzl@7050 | 191 | |
tschatzl@7050 | 192 | if (length_found == num) { |
tschatzl@7050 | 193 | for (uint i = found; i < (found + num); i++) { |
tschatzl@7050 | 194 | HeapRegion* hr = _regions.get_by_index(i); |
tschatzl@7050 | 195 | // sanity check |
tschatzl@7050 | 196 | guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()), |
tschatzl@7050 | 197 | err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT |
tschatzl@7050 | 198 | " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr))); |
tschatzl@7050 | 199 | } |
tschatzl@7050 | 200 | return found; |
tschatzl@7050 | 201 | } else { |
tschatzl@7050 | 202 | return G1_NO_HRS_INDEX; |
tschatzl@7050 | 203 | } |
ysr@777 | 204 | } |
ysr@777 | 205 | |
tschatzl@7050 | 206 | HeapRegion* HeapRegionSeq::next_region_in_heap(const HeapRegion* r) const { |
tschatzl@7050 | 207 | guarantee(r != NULL, "Start region must be a valid region"); |
tschatzl@7050 | 208 | guarantee(is_available(r->hrs_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrs_index())); |
tschatzl@7050 | 209 | for (uint i = r->hrs_index() + 1; i < _allocated_heapregions_length; i++) { |
tschatzl@7050 | 210 | HeapRegion* hr = _regions.get_by_index(i); |
tschatzl@7050 | 211 | if (is_available(i)) { |
tschatzl@7050 | 212 | return hr; |
tschatzl@7050 | 213 | } |
tonyp@2963 | 214 | } |
tschatzl@7050 | 215 | return NULL; |
ysr@777 | 216 | } |
ysr@777 | 217 | |
tonyp@2963 | 218 | void HeapRegionSeq::iterate(HeapRegionClosure* blk) const { |
tschatzl@7050 | 219 | uint len = max_length(); |
ysr@777 | 220 | |
tschatzl@7050 | 221 | for (uint i = 0; i < len; i++) { |
tschatzl@7050 | 222 | if (!is_available(i)) { |
tschatzl@7050 | 223 | continue; |
ysr@777 | 224 | } |
tschatzl@7050 | 225 | guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i)); |
tonyp@2963 | 226 | bool res = blk->doHeapRegion(at(i)); |
ysr@777 | 227 | if (res) { |
ysr@777 | 228 | blk->incomplete(); |
ysr@777 | 229 | return; |
ysr@777 | 230 | } |
ysr@777 | 231 | } |
ysr@777 | 232 | } |
ysr@777 | 233 | |
tschatzl@7050 | 234 | uint HeapRegionSeq::find_unavailable_from_idx(uint start_idx, uint* res_idx) const { |
tschatzl@7050 | 235 | guarantee(res_idx != NULL, "checking"); |
tschatzl@7050 | 236 | guarantee(start_idx <= (max_length() + 1), "checking"); |
tschatzl@7050 | 237 | |
tschatzl@7050 | 238 | uint num_regions = 0; |
tschatzl@7050 | 239 | |
tschatzl@7050 | 240 | uint cur = start_idx; |
tschatzl@7050 | 241 | while (cur < max_length() && is_available(cur)) { |
tschatzl@7050 | 242 | cur++; |
tschatzl@7050 | 243 | } |
tschatzl@7050 | 244 | if (cur == max_length()) { |
tschatzl@7050 | 245 | return num_regions; |
tschatzl@7050 | 246 | } |
tschatzl@7050 | 247 | *res_idx = cur; |
tschatzl@7050 | 248 | while (cur < max_length() && !is_available(cur)) { |
tschatzl@7050 | 249 | cur++; |
tschatzl@7050 | 250 | } |
tschatzl@7050 | 251 | num_regions = cur - *res_idx; |
tschatzl@7050 | 252 | #ifdef ASSERT |
tschatzl@7050 | 253 | for (uint i = *res_idx; i < (*res_idx + num_regions); i++) { |
tschatzl@7050 | 254 | assert(!is_available(i), "just checking"); |
tschatzl@7050 | 255 | } |
tschatzl@7050 | 256 | assert(cur == max_length() || num_regions == 0 || is_available(cur), |
tschatzl@7050 | 257 | err_msg("The region at the current position %u must be available or at the end of the heap.", cur)); |
tschatzl@7050 | 258 | #endif |
tschatzl@7050 | 259 | return num_regions; |
tschatzl@7050 | 260 | } |
tschatzl@7050 | 261 | |
tschatzl@7050 | 262 | uint HeapRegionSeq::start_region_for_worker(uint worker_i, uint num_workers, uint num_regions) const { |
tschatzl@7050 | 263 | return num_regions * worker_i / num_workers; |
tschatzl@7050 | 264 | } |
tschatzl@7050 | 265 | |
tschatzl@7050 | 266 | void HeapRegionSeq::par_iterate(HeapRegionClosure* blk, uint worker_id, uint num_workers, jint claim_value) const { |
tschatzl@7050 | 267 | const uint start_index = start_region_for_worker(worker_id, num_workers, _allocated_heapregions_length); |
tschatzl@7050 | 268 | |
tschatzl@7050 | 269 | // Every worker will actually look at all regions, skipping over regions that |
tschatzl@7050 | 270 | // are currently not committed. |
tschatzl@7050 | 271 | // This also (potentially) iterates over regions newly allocated during GC. This |
tschatzl@7050 | 272 | // is no problem except for some extra work. |
tschatzl@7050 | 273 | for (uint count = 0; count < _allocated_heapregions_length; count++) { |
tschatzl@7050 | 274 | const uint index = (start_index + count) % _allocated_heapregions_length; |
tschatzl@7050 | 275 | assert(0 <= index && index < _allocated_heapregions_length, "sanity"); |
tschatzl@7050 | 276 | // Skip over unavailable regions |
tschatzl@7050 | 277 | if (!is_available(index)) { |
tschatzl@7050 | 278 | continue; |
tschatzl@7050 | 279 | } |
tschatzl@7050 | 280 | HeapRegion* r = _regions.get_by_index(index); |
tschatzl@7050 | 281 | // We'll ignore "continues humongous" regions (we'll process them |
tschatzl@7050 | 282 | // when we come across their corresponding "start humongous" |
tschatzl@7050 | 283 | // region) and regions already claimed. |
tschatzl@7050 | 284 | if (r->claim_value() == claim_value || r->continuesHumongous()) { |
tschatzl@7050 | 285 | continue; |
tschatzl@7050 | 286 | } |
tschatzl@7050 | 287 | // OK, try to claim it |
tschatzl@7050 | 288 | if (!r->claimHeapRegion(claim_value)) { |
tschatzl@7050 | 289 | continue; |
tschatzl@7050 | 290 | } |
tschatzl@7050 | 291 | // Success! |
tschatzl@7050 | 292 | if (r->startsHumongous()) { |
tschatzl@7050 | 293 | // If the region is "starts humongous" we'll iterate over its |
tschatzl@7050 | 294 | // "continues humongous" first; in fact we'll do them |
tschatzl@7050 | 295 | // first. The order is important. In one case, calling the |
tschatzl@7050 | 296 | // closure on the "starts humongous" region might de-allocate |
tschatzl@7050 | 297 | // and clear all its "continues humongous" regions and, as a |
tschatzl@7050 | 298 | // result, we might end up processing them twice. So, we'll do |
tschatzl@7050 | 299 | // them first (note: most closures will ignore them anyway) and |
tschatzl@7050 | 300 | // then we'll do the "starts humongous" region. |
tschatzl@7050 | 301 | for (uint ch_index = index + 1; ch_index < index + r->region_num(); ch_index++) { |
tschatzl@7050 | 302 | HeapRegion* chr = _regions.get_by_index(ch_index); |
tschatzl@7050 | 303 | |
tschatzl@7050 | 304 | assert(chr->continuesHumongous(), "Must be humongous region"); |
tschatzl@7050 | 305 | assert(chr->humongous_start_region() == r, |
tschatzl@7050 | 306 | err_msg("Must work on humongous continuation of the original start region " |
tschatzl@7050 | 307 | PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr))); |
tschatzl@7050 | 308 | assert(chr->claim_value() != claim_value, |
tschatzl@7050 | 309 | "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); |
tschatzl@7050 | 310 | |
tschatzl@7050 | 311 | bool claim_result = chr->claimHeapRegion(claim_value); |
tschatzl@7050 | 312 | // We should always be able to claim it; no one else should |
tschatzl@7050 | 313 | // be trying to claim this region. |
tschatzl@7050 | 314 | guarantee(claim_result, "We should always be able to claim the continuesHumongous part of the humongous object"); |
tschatzl@7050 | 315 | |
tschatzl@7050 | 316 | bool res2 = blk->doHeapRegion(chr); |
tschatzl@7050 | 317 | if (res2) { |
tschatzl@7050 | 318 | return; |
tschatzl@7050 | 319 | } |
tschatzl@7050 | 320 | |
tschatzl@7050 | 321 | // Right now, this holds (i.e., no closure that actually |
tschatzl@7050 | 322 | // does something with "continues humongous" regions |
tschatzl@7050 | 323 | // clears them). We might have to weaken it in the future, |
tschatzl@7050 | 324 | // but let's leave these two asserts here for extra safety. |
tschatzl@7050 | 325 | assert(chr->continuesHumongous(), "should still be the case"); |
tschatzl@7050 | 326 | assert(chr->humongous_start_region() == r, "sanity"); |
tschatzl@7050 | 327 | } |
tschatzl@7050 | 328 | } |
tschatzl@7050 | 329 | |
tschatzl@7050 | 330 | bool res = blk->doHeapRegion(r); |
tschatzl@7050 | 331 | if (res) { |
tschatzl@7050 | 332 | return; |
tschatzl@7050 | 333 | } |
tschatzl@7050 | 334 | } |
tschatzl@7050 | 335 | } |
tschatzl@7050 | 336 | |
brutisso@5074 | 337 | uint HeapRegionSeq::shrink_by(uint num_regions_to_remove) { |
tonyp@2963 | 338 | assert(length() > 0, "the region sequence should not be empty"); |
tschatzl@7050 | 339 | assert(length() <= _allocated_heapregions_length, "invariant"); |
tschatzl@7050 | 340 | assert(_allocated_heapregions_length > 0, "we should have at least one region committed"); |
brutisso@5074 | 341 | assert(num_regions_to_remove < length(), "We should never remove all regions"); |
ysr@777 | 342 | |
tschatzl@7050 | 343 | if (num_regions_to_remove == 0) { |
tschatzl@7050 | 344 | return 0; |
tschatzl@7050 | 345 | } |
tonyp@2963 | 346 | |
tschatzl@7050 | 347 | uint removed = 0; |
tschatzl@7050 | 348 | uint cur = _allocated_heapregions_length - 1; |
tschatzl@7050 | 349 | uint idx_last_found = 0; |
tschatzl@7050 | 350 | uint num_last_found = 0; |
tschatzl@7050 | 351 | |
tschatzl@7051 | 352 | while ((removed < num_regions_to_remove) && |
tschatzl@7051 | 353 | (num_last_found = find_empty_from_idx_reverse(cur, &idx_last_found)) > 0) { |
tschatzl@7050 | 354 | // Only allow uncommit from the end of the heap. |
tschatzl@7050 | 355 | if ((idx_last_found + num_last_found) != _allocated_heapregions_length) { |
tschatzl@7050 | 356 | return 0; |
tschatzl@7050 | 357 | } |
tschatzl@7050 | 358 | uint to_remove = MIN2(num_regions_to_remove - removed, num_last_found); |
tschatzl@7050 | 359 | |
tschatzl@7050 | 360 | uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove); |
tschatzl@7050 | 361 | |
tschatzl@7050 | 362 | cur -= num_last_found; |
tschatzl@7050 | 363 | removed += to_remove; |
ysr@777 | 364 | } |
brutisso@5074 | 365 | |
tschatzl@7050 | 366 | verify_optional(); |
tschatzl@7050 | 367 | |
tschatzl@7050 | 368 | return removed; |
ysr@777 | 369 | } |
ysr@777 | 370 | |
tschatzl@7050 | 371 | uint HeapRegionSeq::find_empty_from_idx_reverse(uint start_idx, uint* res_idx) const { |
tschatzl@7050 | 372 | guarantee(start_idx < _allocated_heapregions_length, "checking"); |
tschatzl@7050 | 373 | guarantee(res_idx != NULL, "checking"); |
tschatzl@7050 | 374 | |
tschatzl@7050 | 375 | uint num_regions_found = 0; |
tschatzl@7050 | 376 | |
tschatzl@7050 | 377 | jlong cur = start_idx; |
tschatzl@7050 | 378 | while (cur != -1 && !(is_available(cur) && at(cur)->is_empty())) { |
tschatzl@7050 | 379 | cur--; |
tschatzl@7050 | 380 | } |
tschatzl@7050 | 381 | if (cur == -1) { |
tschatzl@7050 | 382 | return num_regions_found; |
tschatzl@7050 | 383 | } |
tschatzl@7050 | 384 | jlong old_cur = cur; |
tschatzl@7050 | 385 | // cur indexes the first empty region |
tschatzl@7050 | 386 | while (cur != -1 && is_available(cur) && at(cur)->is_empty()) { |
tschatzl@7050 | 387 | cur--; |
tschatzl@7050 | 388 | } |
tschatzl@7050 | 389 | *res_idx = cur + 1; |
tschatzl@7050 | 390 | num_regions_found = old_cur - cur; |
tschatzl@7050 | 391 | |
tschatzl@7050 | 392 | #ifdef ASSERT |
tschatzl@7050 | 393 | for (uint i = *res_idx; i < (*res_idx + num_regions_found); i++) { |
tschatzl@7050 | 394 | assert(at(i)->is_empty(), "just checking"); |
tschatzl@7050 | 395 | } |
tschatzl@7050 | 396 | #endif |
tschatzl@7050 | 397 | return num_regions_found; |
tschatzl@7050 | 398 | } |
tschatzl@7050 | 399 | |
tschatzl@7050 | 400 | void HeapRegionSeq::verify() { |
tschatzl@7050 | 401 | guarantee(length() <= _allocated_heapregions_length, |
tonyp@3713 | 402 | err_msg("invariant: _length: %u _allocated_length: %u", |
tschatzl@7050 | 403 | length(), _allocated_heapregions_length)); |
tschatzl@7050 | 404 | guarantee(_allocated_heapregions_length <= max_length(), |
tonyp@3713 | 405 | err_msg("invariant: _allocated_length: %u _max_length: %u", |
tschatzl@7050 | 406 | _allocated_heapregions_length, max_length())); |
tonyp@2963 | 407 | |
tschatzl@7050 | 408 | bool prev_committed = true; |
tschatzl@7050 | 409 | uint num_committed = 0; |
tschatzl@5773 | 410 | HeapWord* prev_end = heap_bottom(); |
tschatzl@7050 | 411 | for (uint i = 0; i < _allocated_heapregions_length; i++) { |
tschatzl@7050 | 412 | if (!is_available(i)) { |
tschatzl@7050 | 413 | prev_committed = false; |
tschatzl@7050 | 414 | continue; |
tschatzl@7050 | 415 | } |
tschatzl@7050 | 416 | num_committed++; |
tschatzl@5773 | 417 | HeapRegion* hr = _regions.get_by_index(i); |
tonyp@3713 | 418 | guarantee(hr != NULL, err_msg("invariant: i: %u", i)); |
tschatzl@7050 | 419 | guarantee(!prev_committed || hr->bottom() == prev_end, |
tonyp@3713 | 420 | err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT, |
drchase@6680 | 421 | i, HR_FORMAT_PARAMS(hr), p2i(prev_end))); |
tonyp@2963 | 422 | guarantee(hr->hrs_index() == i, |
tonyp@3713 | 423 | err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index())); |
tschatzl@7050 | 424 | // Asserts will fire if i is >= _length |
tschatzl@7050 | 425 | HeapWord* addr = hr->bottom(); |
tschatzl@7050 | 426 | guarantee(addr_to_region(addr) == hr, "sanity"); |
tschatzl@7050 | 427 | // We cannot check whether the region is part of a particular set: at the time |
tschatzl@7050 | 428 | // this method may be called, we have only completed allocation of the regions, |
tschatzl@7050 | 429 | // but not put into a region set. |
tschatzl@7050 | 430 | prev_committed = true; |
tonyp@2963 | 431 | if (hr->startsHumongous()) { |
tonyp@2963 | 432 | prev_end = hr->orig_end(); |
tonyp@2963 | 433 | } else { |
tonyp@2963 | 434 | prev_end = hr->end(); |
tonyp@2963 | 435 | } |
ysr@777 | 436 | } |
tschatzl@7050 | 437 | for (uint i = _allocated_heapregions_length; i < max_length(); i++) { |
tschatzl@5773 | 438 | guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i)); |
tonyp@2963 | 439 | } |
tschatzl@7050 | 440 | |
tschatzl@7050 | 441 | guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); |
tschatzl@7050 | 442 | _free_list.verify(); |
tschatzl@7050 | 443 | } |
tschatzl@7050 | 444 | |
tschatzl@7050 | 445 | #ifndef PRODUCT |
tschatzl@7050 | 446 | void HeapRegionSeq::verify_optional() { |
tschatzl@7050 | 447 | verify(); |
ysr@777 | 448 | } |
tonyp@2963 | 449 | #endif // PRODUCT |
tschatzl@7050 | 450 |