annotate src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @ 453:c96030fff130

6684579: SoftReference processing can be made more efficient Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not. Reviewed-by: jmasa
author ysr
date Thu, 20 Nov 2008 16:56:09 -0800
parents 850fdf70db2b
children df4305d4c1a1
rev   line source
duke@0 1 /*
xdono@196 2 * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
duke@0 7 * published by the Free Software Foundation.
duke@0 8 *
duke@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 13 * accompanied this code).
duke@0 14 *
duke@0 15 * You should have received a copy of the GNU General Public License version
duke@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 18 *
duke@0 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@0 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@0 21 * have any questions.
duke@0 22 *
duke@0 23 */
duke@0 24
duke@0 25 # include "incls/_precompiled.incl"
duke@0 26 # include "incls/_parNewGeneration.cpp.incl"
duke@0 27
duke@0 28 #ifdef _MSC_VER
duke@0 29 #pragma warning( push )
duke@0 30 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list
duke@0 31 #endif
duke@0 32 ParScanThreadState::ParScanThreadState(Space* to_space_,
duke@0 33 ParNewGeneration* gen_,
duke@0 34 Generation* old_gen_,
duke@0 35 int thread_num_,
duke@0 36 ObjToScanQueueSet* work_queue_set_,
duke@0 37 size_t desired_plab_sz_,
duke@0 38 ParallelTaskTerminator& term_) :
duke@0 39 _to_space(to_space_), _old_gen(old_gen_), _thread_num(thread_num_),
duke@0 40 _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false),
duke@0 41 _ageTable(false), // false ==> not the global age table, no perf data.
duke@0 42 _to_space_alloc_buffer(desired_plab_sz_),
duke@0 43 _to_space_closure(gen_, this), _old_gen_closure(gen_, this),
duke@0 44 _to_space_root_closure(gen_, this), _old_gen_root_closure(gen_, this),
duke@0 45 _older_gen_closure(gen_, this),
duke@0 46 _evacuate_followers(this, &_to_space_closure, &_old_gen_closure,
duke@0 47 &_to_space_root_closure, gen_, &_old_gen_root_closure,
duke@0 48 work_queue_set_, &term_),
duke@0 49 _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
duke@0 50 _keep_alive_closure(&_scan_weak_ref_closure),
duke@0 51 _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0),
duke@0 52 _strong_roots_time(0.0), _term_time(0.0)
duke@0 53 {
duke@0 54 _survivor_chunk_array =
duke@0 55 (ChunkArray*) old_gen()->get_data_recorder(thread_num());
duke@0 56 _hash_seed = 17; // Might want to take time-based random value.
duke@0 57 _start = os::elapsedTime();
duke@0 58 _old_gen_closure.set_generation(old_gen_);
duke@0 59 _old_gen_root_closure.set_generation(old_gen_);
duke@0 60 }
duke@0 61 #ifdef _MSC_VER
duke@0 62 #pragma warning( pop )
duke@0 63 #endif
duke@0 64
duke@0 65 void ParScanThreadState::record_survivor_plab(HeapWord* plab_start,
duke@0 66 size_t plab_word_size) {
duke@0 67 ChunkArray* sca = survivor_chunk_array();
duke@0 68 if (sca != NULL) {
duke@0 69 // A non-null SCA implies that we want the PLAB data recorded.
duke@0 70 sca->record_sample(plab_start, plab_word_size);
duke@0 71 }
duke@0 72 }
duke@0 73
duke@0 74 bool ParScanThreadState::should_be_partially_scanned(oop new_obj, oop old_obj) const {
duke@0 75 return new_obj->is_objArray() &&
duke@0 76 arrayOop(new_obj)->length() > ParGCArrayScanChunk &&
duke@0 77 new_obj != old_obj;
duke@0 78 }
duke@0 79
duke@0 80 void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) {
duke@0 81 assert(old->is_objArray(), "must be obj array");
duke@0 82 assert(old->is_forwarded(), "must be forwarded");
duke@0 83 assert(Universe::heap()->is_in_reserved(old), "must be in heap.");
duke@0 84 assert(!_old_gen->is_in(old), "must be in young generation.");
duke@0 85
duke@0 86 objArrayOop obj = objArrayOop(old->forwardee());
duke@0 87 // Process ParGCArrayScanChunk elements now
duke@0 88 // and push the remainder back onto queue
duke@0 89 int start = arrayOop(old)->length();
duke@0 90 int end = obj->length();
duke@0 91 int remainder = end - start;
duke@0 92 assert(start <= end, "just checking");
duke@0 93 if (remainder > 2 * ParGCArrayScanChunk) {
duke@0 94 // Test above combines last partial chunk with a full chunk
duke@0 95 end = start + ParGCArrayScanChunk;
duke@0 96 arrayOop(old)->set_length(end);
duke@0 97 // Push remainder.
duke@0 98 bool ok = work_queue()->push(old);
duke@0 99 assert(ok, "just popped, push must be okay");
duke@0 100 note_push();
duke@0 101 } else {
duke@0 102 // Restore length so that it can be used if there
duke@0 103 // is a promotion failure and forwarding pointers
duke@0 104 // must be removed.
duke@0 105 arrayOop(old)->set_length(end);
duke@0 106 }
coleenp@113 107
duke@0 108 // process our set of indices (include header in first chunk)
coleenp@113 109 // should make sure end is even (aligned to HeapWord in case of compressed oops)
duke@0 110 if ((HeapWord *)obj < young_old_boundary()) {
duke@0 111 // object is in to_space
coleenp@113 112 obj->oop_iterate_range(&_to_space_closure, start, end);
duke@0 113 } else {
duke@0 114 // object is in old generation
coleenp@113 115 obj->oop_iterate_range(&_old_gen_closure, start, end);
duke@0 116 }
duke@0 117 }
duke@0 118
duke@0 119
duke@0 120 void ParScanThreadState::trim_queues(int max_size) {
duke@0 121 ObjToScanQueue* queue = work_queue();
duke@0 122 while (queue->size() > (juint)max_size) {
duke@0 123 oop obj_to_scan;
duke@0 124 if (queue->pop_local(obj_to_scan)) {
duke@0 125 note_pop();
duke@0 126
duke@0 127 if ((HeapWord *)obj_to_scan < young_old_boundary()) {
duke@0 128 if (obj_to_scan->is_objArray() &&
duke@0 129 obj_to_scan->is_forwarded() &&
duke@0 130 obj_to_scan->forwardee() != obj_to_scan) {
duke@0 131 scan_partial_array_and_push_remainder(obj_to_scan);
duke@0 132 } else {
duke@0 133 // object is in to_space
duke@0 134 obj_to_scan->oop_iterate(&_to_space_closure);
duke@0 135 }
duke@0 136 } else {
duke@0 137 // object is in old generation
duke@0 138 obj_to_scan->oop_iterate(&_old_gen_closure);
duke@0 139 }
duke@0 140 }
duke@0 141 }
duke@0 142 }
duke@0 143
duke@0 144 HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) {
duke@0 145
duke@0 146 // Otherwise, if the object is small enough, try to reallocate the
duke@0 147 // buffer.
duke@0 148 HeapWord* obj = NULL;
duke@0 149 if (!_to_space_full) {
duke@0 150 ParGCAllocBuffer* const plab = to_space_alloc_buffer();
duke@0 151 Space* const sp = to_space();
duke@0 152 if (word_sz * 100 <
duke@0 153 ParallelGCBufferWastePct * plab->word_sz()) {
duke@0 154 // Is small enough; abandon this buffer and start a new one.
duke@0 155 plab->retire(false, false);
duke@0 156 size_t buf_size = plab->word_sz();
duke@0 157 HeapWord* buf_space = sp->par_allocate(buf_size);
duke@0 158 if (buf_space == NULL) {
duke@0 159 const size_t min_bytes =
duke@0 160 ParGCAllocBuffer::min_size() << LogHeapWordSize;
duke@0 161 size_t free_bytes = sp->free();
duke@0 162 while(buf_space == NULL && free_bytes >= min_bytes) {
duke@0 163 buf_size = free_bytes >> LogHeapWordSize;
duke@0 164 assert(buf_size == (size_t)align_object_size(buf_size),
duke@0 165 "Invariant");
duke@0 166 buf_space = sp->par_allocate(buf_size);
duke@0 167 free_bytes = sp->free();
duke@0 168 }
duke@0 169 }
duke@0 170 if (buf_space != NULL) {
duke@0 171 plab->set_word_size(buf_size);
duke@0 172 plab->set_buf(buf_space);
duke@0 173 record_survivor_plab(buf_space, buf_size);
duke@0 174 obj = plab->allocate(word_sz);
duke@0 175 // Note that we cannot compare buf_size < word_sz below
duke@0 176 // because of AlignmentReserve (see ParGCAllocBuffer::allocate()).
duke@0 177 assert(obj != NULL || plab->words_remaining() < word_sz,
duke@0 178 "Else should have been able to allocate");
duke@0 179 // It's conceivable that we may be able to use the
duke@0 180 // buffer we just grabbed for subsequent small requests
duke@0 181 // even if not for this one.
duke@0 182 } else {
duke@0 183 // We're used up.
duke@0 184 _to_space_full = true;
duke@0 185 }
duke@0 186
duke@0 187 } else {
duke@0 188 // Too large; allocate the object individually.
duke@0 189 obj = sp->par_allocate(word_sz);
duke@0 190 }
duke@0 191 }
duke@0 192 return obj;
duke@0 193 }
duke@0 194
duke@0 195
duke@0 196 void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj,
duke@0 197 size_t word_sz) {
duke@0 198 // Is the alloc in the current alloc buffer?
duke@0 199 if (to_space_alloc_buffer()->contains(obj)) {
duke@0 200 assert(to_space_alloc_buffer()->contains(obj + word_sz - 1),
duke@0 201 "Should contain whole object.");
duke@0 202 to_space_alloc_buffer()->undo_allocation(obj, word_sz);
duke@0 203 } else {
duke@0 204 SharedHeap::fill_region_with_object(MemRegion(obj, word_sz));
duke@0 205 }
duke@0 206 }
duke@0 207
duke@0 208 class ParScanThreadStateSet: private ResourceArray {
duke@0 209 public:
duke@0 210 // Initializes states for the specified number of threads;
duke@0 211 ParScanThreadStateSet(int num_threads,
duke@0 212 Space& to_space,
duke@0 213 ParNewGeneration& gen,
duke@0 214 Generation& old_gen,
duke@0 215 ObjToScanQueueSet& queue_set,
duke@0 216 size_t desired_plab_sz,
duke@0 217 ParallelTaskTerminator& term);
duke@0 218 inline ParScanThreadState& thread_sate(int i);
duke@0 219 int pushes() { return _pushes; }
duke@0 220 int pops() { return _pops; }
duke@0 221 int steals() { return _steals; }
duke@0 222 void reset();
duke@0 223 void flush();
duke@0 224 private:
duke@0 225 ParallelTaskTerminator& _term;
duke@0 226 ParNewGeneration& _gen;
duke@0 227 Generation& _next_gen;
duke@0 228 // staticstics
duke@0 229 int _pushes;
duke@0 230 int _pops;
duke@0 231 int _steals;
duke@0 232 };
duke@0 233
duke@0 234
duke@0 235 ParScanThreadStateSet::ParScanThreadStateSet(
duke@0 236 int num_threads, Space& to_space, ParNewGeneration& gen,
duke@0 237 Generation& old_gen, ObjToScanQueueSet& queue_set,
duke@0 238 size_t desired_plab_sz, ParallelTaskTerminator& term)
duke@0 239 : ResourceArray(sizeof(ParScanThreadState), num_threads),
duke@0 240 _gen(gen), _next_gen(old_gen), _term(term),
duke@0 241 _pushes(0), _pops(0), _steals(0)
duke@0 242 {
duke@0 243 assert(num_threads > 0, "sanity check!");
duke@0 244 // Initialize states.
duke@0 245 for (int i = 0; i < num_threads; ++i) {
duke@0 246 new ((ParScanThreadState*)_data + i)
duke@0 247 ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set,
duke@0 248 desired_plab_sz, term);
duke@0 249 }
duke@0 250 }
duke@0 251
duke@0 252 inline ParScanThreadState& ParScanThreadStateSet::thread_sate(int i)
duke@0 253 {
duke@0 254 assert(i >= 0 && i < length(), "sanity check!");
duke@0 255 return ((ParScanThreadState*)_data)[i];
duke@0 256 }
duke@0 257
duke@0 258
duke@0 259 void ParScanThreadStateSet::reset()
duke@0 260 {
duke@0 261 _term.reset_for_reuse();
duke@0 262 }
duke@0 263
duke@0 264 void ParScanThreadStateSet::flush()
duke@0 265 {
duke@0 266 for (int i = 0; i < length(); ++i) {
duke@0 267 ParScanThreadState& par_scan_state = thread_sate(i);
duke@0 268
duke@0 269 // Flush stats related to To-space PLAB activity and
duke@0 270 // retire the last buffer.
duke@0 271 par_scan_state.to_space_alloc_buffer()->
duke@0 272 flush_stats_and_retire(_gen.plab_stats(),
duke@0 273 false /* !retain */);
duke@0 274
duke@0 275 // Every thread has its own age table. We need to merge
duke@0 276 // them all into one.
duke@0 277 ageTable *local_table = par_scan_state.age_table();
duke@0 278 _gen.age_table()->merge(local_table);
duke@0 279
duke@0 280 // Inform old gen that we're done.
duke@0 281 _next_gen.par_promote_alloc_done(i);
duke@0 282 _next_gen.par_oop_since_save_marks_iterate_done(i);
duke@0 283
duke@0 284 // Flush stats related to work queue activity (push/pop/steal)
duke@0 285 // This could conceivably become a bottleneck; if so, we'll put the
duke@0 286 // stat's gathering under the flag.
duke@0 287 if (PAR_STATS_ENABLED) {
duke@0 288 _pushes += par_scan_state.pushes();
duke@0 289 _pops += par_scan_state.pops();
duke@0 290 _steals += par_scan_state.steals();
duke@0 291 if (ParallelGCVerbose) {
duke@0 292 gclog_or_tty->print("Thread %d complete:\n"
duke@0 293 " Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n",
duke@0 294 i, par_scan_state.pushes(), par_scan_state.pops(),
duke@0 295 par_scan_state.steals(), par_scan_state.steal_attempts());
duke@0 296 if (par_scan_state.overflow_pushes() > 0 ||
duke@0 297 par_scan_state.overflow_refills() > 0) {
duke@0 298 gclog_or_tty->print(" Overflow pushes: %7d "
duke@0 299 "Overflow refills: %7d for %d objs.\n",
duke@0 300 par_scan_state.overflow_pushes(),
duke@0 301 par_scan_state.overflow_refills(),
duke@0 302 par_scan_state.overflow_refill_objs());
duke@0 303 }
duke@0 304
duke@0 305 double elapsed = par_scan_state.elapsed();
duke@0 306 double strong_roots = par_scan_state.strong_roots_time();
duke@0 307 double term = par_scan_state.term_time();
duke@0 308 gclog_or_tty->print(
duke@0 309 " Elapsed: %7.2f ms.\n"
duke@0 310 " Strong roots: %7.2f ms (%6.2f%%)\n"
duke@0 311 " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n",
duke@0 312 elapsed * 1000.0,
duke@0 313 strong_roots * 1000.0, (strong_roots*100.0/elapsed),
duke@0 314 term * 1000.0, (term*100.0/elapsed),
duke@0 315 par_scan_state.term_attempts());
duke@0 316 }
duke@0 317 }
duke@0 318 }
duke@0 319 }
duke@0 320
duke@0 321 ParScanClosure::ParScanClosure(ParNewGeneration* g,
duke@0 322 ParScanThreadState* par_scan_state) :
duke@0 323 OopsInGenClosure(g), _par_scan_state(par_scan_state), _g(g)
duke@0 324 {
duke@0 325 assert(_g->level() == 0, "Optimized for youngest generation");
duke@0 326 _boundary = _g->reserved().end();
duke@0 327 }
duke@0 328
coleenp@113 329 void ParScanWithBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, true, false); }
coleenp@113 330 void ParScanWithBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, true, false); }
coleenp@113 331
coleenp@113 332 void ParScanWithoutBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, false, false); }
coleenp@113 333 void ParScanWithoutBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, false, false); }
coleenp@113 334
coleenp@113 335 void ParRootScanWithBarrierTwoGensClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, true, true); }
coleenp@113 336 void ParRootScanWithBarrierTwoGensClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, true, true); }
coleenp@113 337
coleenp@113 338 void ParRootScanWithoutBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, false, true); }
coleenp@113 339 void ParRootScanWithoutBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, false, true); }
coleenp@113 340
duke@0 341 ParScanWeakRefClosure::ParScanWeakRefClosure(ParNewGeneration* g,
duke@0 342 ParScanThreadState* par_scan_state)
duke@0 343 : ScanWeakRefClosure(g), _par_scan_state(par_scan_state)
coleenp@113 344 {}
coleenp@113 345
coleenp@113 346 void ParScanWeakRefClosure::do_oop(oop* p) { ParScanWeakRefClosure::do_oop_work(p); }
coleenp@113 347 void ParScanWeakRefClosure::do_oop(narrowOop* p) { ParScanWeakRefClosure::do_oop_work(p); }
duke@0 348
duke@0 349 #ifdef WIN32
duke@0 350 #pragma warning(disable: 4786) /* identifier was truncated to '255' characters in the browser information */
duke@0 351 #endif
duke@0 352
duke@0 353 ParEvacuateFollowersClosure::ParEvacuateFollowersClosure(
duke@0 354 ParScanThreadState* par_scan_state_,
duke@0 355 ParScanWithoutBarrierClosure* to_space_closure_,
duke@0 356 ParScanWithBarrierClosure* old_gen_closure_,
duke@0 357 ParRootScanWithoutBarrierClosure* to_space_root_closure_,
duke@0 358 ParNewGeneration* par_gen_,
duke@0 359 ParRootScanWithBarrierTwoGensClosure* old_gen_root_closure_,
duke@0 360 ObjToScanQueueSet* task_queues_,
duke@0 361 ParallelTaskTerminator* terminator_) :
duke@0 362
duke@0 363 _par_scan_state(par_scan_state_),
duke@0 364 _to_space_closure(to_space_closure_),
duke@0 365 _old_gen_closure(old_gen_closure_),
duke@0 366 _to_space_root_closure(to_space_root_closure_),
duke@0 367 _old_gen_root_closure(old_gen_root_closure_),
duke@0 368 _par_gen(par_gen_),
duke@0 369 _task_queues(task_queues_),
duke@0 370 _terminator(terminator_)
duke@0 371 {}
duke@0 372
duke@0 373 void ParEvacuateFollowersClosure::do_void() {
duke@0 374 ObjToScanQueue* work_q = par_scan_state()->work_queue();
duke@0 375
duke@0 376 while (true) {
duke@0 377
duke@0 378 // Scan to-space and old-gen objs until we run out of both.
duke@0 379 oop obj_to_scan;
duke@0 380 par_scan_state()->trim_queues(0);
duke@0 381
duke@0 382 // We have no local work, attempt to steal from other threads.
duke@0 383
duke@0 384 // attempt to steal work from promoted.
duke@0 385 par_scan_state()->note_steal_attempt();
duke@0 386 if (task_queues()->steal(par_scan_state()->thread_num(),
duke@0 387 par_scan_state()->hash_seed(),
duke@0 388 obj_to_scan)) {
duke@0 389 par_scan_state()->note_steal();
duke@0 390 bool res = work_q->push(obj_to_scan);
duke@0 391 assert(res, "Empty queue should have room for a push.");
duke@0 392
duke@0 393 par_scan_state()->note_push();
duke@0 394 // if successful, goto Start.
duke@0 395 continue;
duke@0 396
duke@0 397 // try global overflow list.
duke@0 398 } else if (par_gen()->take_from_overflow_list(par_scan_state())) {
duke@0 399 continue;
duke@0 400 }
duke@0 401
duke@0 402 // Otherwise, offer termination.
duke@0 403 par_scan_state()->start_term_time();
duke@0 404 if (terminator()->offer_termination()) break;
duke@0 405 par_scan_state()->end_term_time();
duke@0 406 }
duke@0 407 // Finish the last termination pause.
duke@0 408 par_scan_state()->end_term_time();
duke@0 409 }
duke@0 410
duke@0 411 ParNewGenTask::ParNewGenTask(ParNewGeneration* gen, Generation* next_gen,
duke@0 412 HeapWord* young_old_boundary, ParScanThreadStateSet* state_set) :
duke@0 413 AbstractGangTask("ParNewGeneration collection"),
duke@0 414 _gen(gen), _next_gen(next_gen),
duke@0 415 _young_old_boundary(young_old_boundary),
duke@0 416 _state_set(state_set)
duke@0 417 {}
duke@0 418
duke@0 419 void ParNewGenTask::work(int i) {
duke@0 420 GenCollectedHeap* gch = GenCollectedHeap::heap();
duke@0 421 // Since this is being done in a separate thread, need new resource
duke@0 422 // and handle marks.
duke@0 423 ResourceMark rm;
duke@0 424 HandleMark hm;
duke@0 425 // We would need multiple old-gen queues otherwise.
duke@0 426 guarantee(gch->n_gens() == 2,
duke@0 427 "Par young collection currently only works with one older gen.");
duke@0 428
duke@0 429 Generation* old_gen = gch->next_gen(_gen);
duke@0 430
duke@0 431 ParScanThreadState& par_scan_state = _state_set->thread_sate(i);
duke@0 432 par_scan_state.set_young_old_boundary(_young_old_boundary);
duke@0 433
duke@0 434 par_scan_state.start_strong_roots();
duke@0 435 gch->gen_process_strong_roots(_gen->level(),
duke@0 436 true, // Process younger gens, if any,
duke@0 437 // as strong roots.
duke@0 438 false,// not collecting perm generation.
duke@0 439 SharedHeap::SO_AllClasses,
duke@0 440 &par_scan_state.older_gen_closure(),
duke@0 441 &par_scan_state.to_space_root_closure());
duke@0 442 par_scan_state.end_strong_roots();
duke@0 443
duke@0 444 // "evacuate followers".
duke@0 445 par_scan_state.evacuate_followers_closure().do_void();
duke@0 446 }
duke@0 447
duke@0 448 #ifdef _MSC_VER
duke@0 449 #pragma warning( push )
duke@0 450 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list
duke@0 451 #endif
duke@0 452 ParNewGeneration::
duke@0 453 ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level)
duke@0 454 : DefNewGeneration(rs, initial_byte_size, level, "PCopy"),
duke@0 455 _overflow_list(NULL),
duke@0 456 _is_alive_closure(this),
duke@0 457 _plab_stats(YoungPLABSize, PLABWeight)
duke@0 458 {
duke@0 459 _task_queues = new ObjToScanQueueSet(ParallelGCThreads);
duke@0 460 guarantee(_task_queues != NULL, "task_queues allocation failure.");
duke@0 461
duke@0 462 for (uint i1 = 0; i1 < ParallelGCThreads; i1++) {
duke@0 463 ObjToScanQueuePadded *q_padded = new ObjToScanQueuePadded();
duke@0 464 guarantee(q_padded != NULL, "work_queue Allocation failure.");
duke@0 465
duke@0 466 _task_queues->register_queue(i1, &q_padded->work_queue);
duke@0 467 }
duke@0 468
duke@0 469 for (uint i2 = 0; i2 < ParallelGCThreads; i2++)
duke@0 470 _task_queues->queue(i2)->initialize();
duke@0 471
duke@0 472 if (UsePerfData) {
duke@0 473 EXCEPTION_MARK;
duke@0 474 ResourceMark rm;
duke@0 475
duke@0 476 const char* cname =
duke@0 477 PerfDataManager::counter_name(_gen_counters->name_space(), "threads");
duke@0 478 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None,
duke@0 479 ParallelGCThreads, CHECK);
duke@0 480 }
duke@0 481 }
duke@0 482 #ifdef _MSC_VER
duke@0 483 #pragma warning( pop )
duke@0 484 #endif
duke@0 485
duke@0 486 // ParNewGeneration::
duke@0 487 ParKeepAliveClosure::ParKeepAliveClosure(ParScanWeakRefClosure* cl) :
duke@0 488 DefNewGeneration::KeepAliveClosure(cl), _par_cl(cl) {}
duke@0 489
coleenp@113 490 template <class T>
coleenp@113 491 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop_work(T* p) {
coleenp@113 492 #ifdef ASSERT
coleenp@113 493 {
coleenp@113 494 assert(!oopDesc::is_null(*p), "expected non-null ref");
coleenp@113 495 oop obj = oopDesc::load_decode_heap_oop_not_null(p);
coleenp@113 496 // We never expect to see a null reference being processed
coleenp@113 497 // as a weak reference.
coleenp@113 498 assert(obj->is_oop(), "expected an oop while scanning weak refs");
coleenp@113 499 }
coleenp@113 500 #endif // ASSERT
duke@0 501
duke@0 502 _par_cl->do_oop_nv(p);
duke@0 503
duke@0 504 if (Universe::heap()->is_in_reserved(p)) {
coleenp@113 505 oop obj = oopDesc::load_decode_heap_oop_not_null(p);
coleenp@113 506 _rs->write_ref_field_gc_par(p, obj);
duke@0 507 }
duke@0 508 }
duke@0 509
coleenp@113 510 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop(oop* p) { ParKeepAliveClosure::do_oop_work(p); }
coleenp@113 511 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop(narrowOop* p) { ParKeepAliveClosure::do_oop_work(p); }
coleenp@113 512
duke@0 513 // ParNewGeneration::
duke@0 514 KeepAliveClosure::KeepAliveClosure(ScanWeakRefClosure* cl) :
duke@0 515 DefNewGeneration::KeepAliveClosure(cl) {}
duke@0 516
coleenp@113 517 template <class T>
coleenp@113 518 void /*ParNewGeneration::*/KeepAliveClosure::do_oop_work(T* p) {
coleenp@113 519 #ifdef ASSERT
coleenp@113 520 {
coleenp@113 521 assert(!oopDesc::is_null(*p), "expected non-null ref");
coleenp@113 522 oop obj = oopDesc::load_decode_heap_oop_not_null(p);
coleenp@113 523 // We never expect to see a null reference being processed
coleenp@113 524 // as a weak reference.
coleenp@113 525 assert(obj->is_oop(), "expected an oop while scanning weak refs");
coleenp@113 526 }
coleenp@113 527 #endif // ASSERT
duke@0 528
duke@0 529 _cl->do_oop_nv(p);
duke@0 530
duke@0 531 if (Universe::heap()->is_in_reserved(p)) {
coleenp@113 532 oop obj = oopDesc::load_decode_heap_oop_not_null(p);
coleenp@113 533 _rs->write_ref_field_gc_par(p, obj);
duke@0 534 }
duke@0 535 }
duke@0 536
coleenp@113 537 void /*ParNewGeneration::*/KeepAliveClosure::do_oop(oop* p) { KeepAliveClosure::do_oop_work(p); }
coleenp@113 538 void /*ParNewGeneration::*/KeepAliveClosure::do_oop(narrowOop* p) { KeepAliveClosure::do_oop_work(p); }
coleenp@113 539
coleenp@113 540 template <class T> void ScanClosureWithParBarrier::do_oop_work(T* p) {
coleenp@113 541 T heap_oop = oopDesc::load_heap_oop(p);
coleenp@113 542 if (!oopDesc::is_null(heap_oop)) {
coleenp@113 543 oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
duke@0 544 if ((HeapWord*)obj < _boundary) {
duke@0 545 assert(!_g->to()->is_in_reserved(obj), "Scanning field twice?");
coleenp@113 546 oop new_obj = obj->is_forwarded()
coleenp@113 547 ? obj->forwardee()
coleenp@113 548 : _g->DefNewGeneration::copy_to_survivor_space(obj);
coleenp@113 549 oopDesc::encode_store_heap_oop_not_null(p, new_obj);
duke@0 550 }
duke@0 551 if (_gc_barrier) {
duke@0 552 // If p points to a younger generation, mark the card.
duke@0 553 if ((HeapWord*)obj < _gen_boundary) {
duke@0 554 _rs->write_ref_field_gc_par(p, obj);
duke@0 555 }
duke@0 556 }
duke@0 557 }
duke@0 558 }
duke@0 559
coleenp@113 560 void ScanClosureWithParBarrier::do_oop(oop* p) { ScanClosureWithParBarrier::do_oop_work(p); }
coleenp@113 561 void ScanClosureWithParBarrier::do_oop(narrowOop* p) { ScanClosureWithParBarrier::do_oop_work(p); }
coleenp@113 562
duke@0 563 class ParNewRefProcTaskProxy: public AbstractGangTask {
duke@0 564 typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
duke@0 565 public:
duke@0 566 ParNewRefProcTaskProxy(ProcessTask& task, ParNewGeneration& gen,
duke@0 567 Generation& next_gen,
duke@0 568 HeapWord* young_old_boundary,
duke@0 569 ParScanThreadStateSet& state_set);
duke@0 570
duke@0 571 private:
duke@0 572 virtual void work(int i);
duke@0 573
duke@0 574 private:
duke@0 575 ParNewGeneration& _gen;
duke@0 576 ProcessTask& _task;
duke@0 577 Generation& _next_gen;
duke@0 578 HeapWord* _young_old_boundary;
duke@0 579 ParScanThreadStateSet& _state_set;
duke@0 580 };
duke@0 581
duke@0 582 ParNewRefProcTaskProxy::ParNewRefProcTaskProxy(
duke@0 583 ProcessTask& task, ParNewGeneration& gen,
duke@0 584 Generation& next_gen,
duke@0 585 HeapWord* young_old_boundary,
duke@0 586 ParScanThreadStateSet& state_set)
duke@0 587 : AbstractGangTask("ParNewGeneration parallel reference processing"),
duke@0 588 _gen(gen),
duke@0 589 _task(task),
duke@0 590 _next_gen(next_gen),
duke@0 591 _young_old_boundary(young_old_boundary),
duke@0 592 _state_set(state_set)
duke@0 593 {
duke@0 594 }
duke@0 595
duke@0 596 void ParNewRefProcTaskProxy::work(int i)
duke@0 597 {
duke@0 598 ResourceMark rm;
duke@0 599 HandleMark hm;
duke@0 600 ParScanThreadState& par_scan_state = _state_set.thread_sate(i);
duke@0 601 par_scan_state.set_young_old_boundary(_young_old_boundary);
duke@0 602 _task.work(i, par_scan_state.is_alive_closure(),
duke@0 603 par_scan_state.keep_alive_closure(),
duke@0 604 par_scan_state.evacuate_followers_closure());
duke@0 605 }
duke@0 606
duke@0 607 class ParNewRefEnqueueTaskProxy: public AbstractGangTask {
duke@0 608 typedef AbstractRefProcTaskExecutor::EnqueueTask EnqueueTask;
duke@0 609 EnqueueTask& _task;
duke@0 610
duke@0 611 public:
duke@0 612 ParNewRefEnqueueTaskProxy(EnqueueTask& task)
duke@0 613 : AbstractGangTask("ParNewGeneration parallel reference enqueue"),
duke@0 614 _task(task)
duke@0 615 { }
duke@0 616
duke@0 617 virtual void work(int i)
duke@0 618 {
duke@0 619 _task.work(i);
duke@0 620 }
duke@0 621 };
duke@0 622
duke@0 623
duke@0 624 void ParNewRefProcTaskExecutor::execute(ProcessTask& task)
duke@0 625 {
duke@0 626 GenCollectedHeap* gch = GenCollectedHeap::heap();
duke@0 627 assert(gch->kind() == CollectedHeap::GenCollectedHeap,
duke@0 628 "not a generational heap");
duke@0 629 WorkGang* workers = gch->workers();
duke@0 630 assert(workers != NULL, "Need parallel worker threads.");
duke@0 631 ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(),
duke@0 632 _generation.reserved().end(), _state_set);
duke@0 633 workers->run_task(&rp_task);
duke@0 634 _state_set.reset();
duke@0 635 }
duke@0 636
duke@0 637 void ParNewRefProcTaskExecutor::execute(EnqueueTask& task)
duke@0 638 {
duke@0 639 GenCollectedHeap* gch = GenCollectedHeap::heap();
duke@0 640 WorkGang* workers = gch->workers();
duke@0 641 assert(workers != NULL, "Need parallel worker threads.");
duke@0 642 ParNewRefEnqueueTaskProxy enq_task(task);
duke@0 643 workers->run_task(&enq_task);
duke@0 644 }
duke@0 645
duke@0 646 void ParNewRefProcTaskExecutor::set_single_threaded_mode()
duke@0 647 {
duke@0 648 _state_set.flush();
duke@0 649 GenCollectedHeap* gch = GenCollectedHeap::heap();
duke@0 650 gch->set_par_threads(0); // 0 ==> non-parallel.
duke@0 651 gch->save_marks();
duke@0 652 }
duke@0 653
duke@0 654 ScanClosureWithParBarrier::
duke@0 655 ScanClosureWithParBarrier(ParNewGeneration* g, bool gc_barrier) :
duke@0 656 ScanClosure(g, gc_barrier) {}
duke@0 657
duke@0 658 EvacuateFollowersClosureGeneral::
duke@0 659 EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, int level,
duke@0 660 OopsInGenClosure* cur,
duke@0 661 OopsInGenClosure* older) :
duke@0 662 _gch(gch), _level(level),
duke@0 663 _scan_cur_or_nonheap(cur), _scan_older(older)
duke@0 664 {}
duke@0 665
duke@0 666 void EvacuateFollowersClosureGeneral::do_void() {
duke@0 667 do {
duke@0 668 // Beware: this call will lead to closure applications via virtual
duke@0 669 // calls.
duke@0 670 _gch->oop_since_save_marks_iterate(_level,
duke@0 671 _scan_cur_or_nonheap,
duke@0 672 _scan_older);
duke@0 673 } while (!_gch->no_allocs_since_save_marks(_level));
duke@0 674 }
duke@0 675
duke@0 676
duke@0 677 bool ParNewGeneration::_avoid_promotion_undo = false;
duke@0 678
duke@0 679 void ParNewGeneration::adjust_desired_tenuring_threshold() {
duke@0 680 // Set the desired survivor size to half the real survivor space
duke@0 681 _tenuring_threshold =
duke@0 682 age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize);
duke@0 683 }
duke@0 684
duke@0 685 // A Generation that does parallel young-gen collection.
duke@0 686
duke@0 687 void ParNewGeneration::collect(bool full,
duke@0 688 bool clear_all_soft_refs,
duke@0 689 size_t size,
duke@0 690 bool is_tlab) {
duke@0 691 assert(full || size > 0, "otherwise we don't want to collect");
duke@0 692 GenCollectedHeap* gch = GenCollectedHeap::heap();
duke@0 693 assert(gch->kind() == CollectedHeap::GenCollectedHeap,
duke@0 694 "not a CMS generational heap");
duke@0 695 AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
duke@0 696 WorkGang* workers = gch->workers();
duke@0 697 _next_gen = gch->next_gen(this);
duke@0 698 assert(_next_gen != NULL,
duke@0 699 "This must be the youngest gen, and not the only gen");
duke@0 700 assert(gch->n_gens() == 2,
duke@0 701 "Par collection currently only works with single older gen.");
duke@0 702 // Do we have to avoid promotion_undo?
duke@0 703 if (gch->collector_policy()->is_concurrent_mark_sweep_policy()) {
duke@0 704 set_avoid_promotion_undo(true);
duke@0 705 }
duke@0 706
duke@0 707 // If the next generation is too full to accomodate worst-case promotion
duke@0 708 // from this generation, pass on collection; let the next generation
duke@0 709 // do it.
duke@0 710 if (!collection_attempt_is_safe()) {
duke@0 711 gch->set_incremental_collection_will_fail();
duke@0 712 return;
duke@0 713 }
duke@0 714 assert(to()->is_empty(), "Else not collection_attempt_is_safe");
duke@0 715
duke@0 716 init_assuming_no_promotion_failure();
duke@0 717
duke@0 718 if (UseAdaptiveSizePolicy) {
duke@0 719 set_survivor_overflow(false);
duke@0 720 size_policy->minor_collection_begin();
duke@0 721 }
duke@0 722
duke@0 723 TraceTime t1("GC", PrintGC && !PrintGCDetails, true, gclog_or_tty);
duke@0 724 // Capture heap used before collection (for printing).
duke@0 725 size_t gch_prev_used = gch->used();
duke@0 726
duke@0 727 SpecializationStats::clear();
duke@0 728
duke@0 729 age_table()->clear();
jmasa@263 730 to()->clear(SpaceDecorator::Mangle);
duke@0 731
duke@0 732 gch->save_marks();
duke@0 733 assert(workers != NULL, "Need parallel worker threads.");
duke@0 734 ParallelTaskTerminator _term(workers->total_workers(), task_queues());
duke@0 735 ParScanThreadStateSet thread_state_set(workers->total_workers(),
duke@0 736 *to(), *this, *_next_gen, *task_queues(),
duke@0 737 desired_plab_sz(), _term);
duke@0 738
duke@0 739 ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set);
duke@0 740 int n_workers = workers->total_workers();
duke@0 741 gch->set_par_threads(n_workers);
duke@0 742 gch->change_strong_roots_parity();
duke@0 743 gch->rem_set()->prepare_for_younger_refs_iterate(true);
duke@0 744 // It turns out that even when we're using 1 thread, doing the work in a
duke@0 745 // separate thread causes wide variance in run times. We can't help this
duke@0 746 // in the multi-threaded case, but we special-case n=1 here to get
duke@0 747 // repeatable measurements of the 1-thread overhead of the parallel code.
duke@0 748 if (n_workers > 1) {
duke@0 749 workers->run_task(&tsk);
duke@0 750 } else {
duke@0 751 tsk.work(0);
duke@0 752 }
duke@0 753 thread_state_set.reset();
duke@0 754
duke@0 755 if (PAR_STATS_ENABLED && ParallelGCVerbose) {
duke@0 756 gclog_or_tty->print("Thread totals:\n"
duke@0 757 " Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n",
duke@0 758 thread_state_set.pushes(), thread_state_set.pops(),
duke@0 759 thread_state_set.steals(),
duke@0 760 thread_state_set.pops()+thread_state_set.steals());
duke@0 761 }
ysr@453 762 assert(thread_state_set.pushes() == thread_state_set.pops()
ysr@453 763 + thread_state_set.steals(),
duke@0 764 "Or else the queues are leaky.");
duke@0 765
duke@0 766 // Process (weak) reference objects found during scavenge.
ysr@453 767 ReferenceProcessor* rp = ref_processor();
duke@0 768 IsAliveClosure is_alive(this);
duke@0 769 ScanWeakRefClosure scan_weak_ref(this);
duke@0 770 KeepAliveClosure keep_alive(&scan_weak_ref);
duke@0 771 ScanClosure scan_without_gc_barrier(this, false);
duke@0 772 ScanClosureWithParBarrier scan_with_gc_barrier(this, true);
duke@0 773 set_promo_failure_scan_stack_closure(&scan_without_gc_barrier);
duke@0 774 EvacuateFollowersClosureGeneral evacuate_followers(gch, _level,
duke@0 775 &scan_without_gc_barrier, &scan_with_gc_barrier);
ysr@453 776 rp->snap_policy(clear_all_soft_refs);
ysr@453 777 if (rp->processing_is_mt()) {
duke@0 778 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
ysr@453 779 rp->process_discovered_references(&is_alive, &keep_alive,
ysr@453 780 &evacuate_followers, &task_executor);
duke@0 781 } else {
duke@0 782 thread_state_set.flush();
duke@0 783 gch->set_par_threads(0); // 0 ==> non-parallel.
duke@0 784 gch->save_marks();
ysr@453 785 rp->process_discovered_references(&is_alive, &keep_alive,
ysr@453 786 &evacuate_followers, NULL);
duke@0 787 }
duke@0 788 if (!promotion_failed()) {
duke@0 789 // Swap the survivor spaces.
jmasa@263 790 eden()->clear(SpaceDecorator::Mangle);
jmasa@263 791 from()->clear(SpaceDecorator::Mangle);
jmasa@263 792 if (ZapUnusedHeapArea) {
jmasa@263 793 // This is now done here because of the piece-meal mangling which
jmasa@263 794 // can check for valid mangling at intermediate points in the
jmasa@263 795 // collection(s). When a minor collection fails to collect
jmasa@263 796 // sufficient space resizing of the young generation can occur
jmasa@263 797 // an redistribute the spaces in the young generation. Mangle
jmasa@263 798 // here so that unzapped regions don't get distributed to
jmasa@263 799 // other spaces.
jmasa@263 800 to()->mangle_unused_area();
jmasa@263 801 }
duke@0 802 swap_spaces();
duke@0 803
duke@0 804 assert(to()->is_empty(), "to space should be empty now");
duke@0 805 } else {
duke@0 806 assert(HandlePromotionFailure,
duke@0 807 "Should only be here if promotion failure handling is on");
duke@0 808 if (_promo_failure_scan_stack != NULL) {
duke@0 809 // Can be non-null because of reference processing.
duke@0 810 // Free stack with its elements.
duke@0 811 delete _promo_failure_scan_stack;
duke@0 812 _promo_failure_scan_stack = NULL;
duke@0 813 }
duke@0 814 remove_forwarding_pointers();
duke@0 815 if (PrintGCDetails) {
duke@0 816 gclog_or_tty->print(" (promotion failed)");
duke@0 817 }
duke@0 818 // All the spaces are in play for mark-sweep.
duke@0 819 swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
duke@0 820 from()->set_next_compaction_space(to());
duke@0 821 gch->set_incremental_collection_will_fail();
jmasa@6 822
jmasa@6 823 // Reset the PromotionFailureALot counters.
jmasa@6 824 NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
duke@0 825 }
duke@0 826 // set new iteration safe limit for the survivor spaces
duke@0 827 from()->set_concurrent_iteration_safe_limit(from()->top());
duke@0 828 to()->set_concurrent_iteration_safe_limit(to()->top());
duke@0 829
duke@0 830 adjust_desired_tenuring_threshold();
duke@0 831 if (ResizePLAB) {
duke@0 832 plab_stats()->adjust_desired_plab_sz();
duke@0 833 }
duke@0 834
duke@0 835 if (PrintGC && !PrintGCDetails) {
duke@0 836 gch->print_heap_change(gch_prev_used);
duke@0 837 }
duke@0 838
duke@0 839 if (UseAdaptiveSizePolicy) {
duke@0 840 size_policy->minor_collection_end(gch->gc_cause());
duke@0 841 size_policy->avg_survived()->sample(from()->used());
duke@0 842 }
duke@0 843
duke@0 844 update_time_of_last_gc(os::javaTimeMillis());
duke@0 845
duke@0 846 SpecializationStats::print();
duke@0 847
ysr@453 848 rp->set_enqueuing_is_done(true);
ysr@453 849 if (rp->processing_is_mt()) {
duke@0 850 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
ysr@453 851 rp->enqueue_discovered_references(&task_executor);
duke@0 852 } else {
ysr@453 853 rp->enqueue_discovered_references(NULL);
duke@0 854 }
ysr@453 855 rp->verify_no_references_recorded();
duke@0 856 }
duke@0 857
duke@0 858 static int sum;
duke@0 859 void ParNewGeneration::waste_some_time() {
duke@0 860 for (int i = 0; i < 100; i++) {
duke@0 861 sum += i;
duke@0 862 }
duke@0 863 }
duke@0 864
duke@0 865 static const oop ClaimedForwardPtr = oop(0x4);
duke@0 866
duke@0 867 // Because of concurrency, there are times where an object for which
duke@0 868 // "is_forwarded()" is true contains an "interim" forwarding pointer
duke@0 869 // value. Such a value will soon be overwritten with a real value.
duke@0 870 // This method requires "obj" to have a forwarding pointer, and waits, if
duke@0 871 // necessary for a real one to be inserted, and returns it.
duke@0 872
duke@0 873 oop ParNewGeneration::real_forwardee(oop obj) {
duke@0 874 oop forward_ptr = obj->forwardee();
duke@0 875 if (forward_ptr != ClaimedForwardPtr) {
duke@0 876 return forward_ptr;
duke@0 877 } else {
duke@0 878 return real_forwardee_slow(obj);
duke@0 879 }
duke@0 880 }
duke@0 881
duke@0 882 oop ParNewGeneration::real_forwardee_slow(oop obj) {
duke@0 883 // Spin-read if it is claimed but not yet written by another thread.
duke@0 884 oop forward_ptr = obj->forwardee();
duke@0 885 while (forward_ptr == ClaimedForwardPtr) {
duke@0 886 waste_some_time();
duke@0 887 assert(obj->is_forwarded(), "precondition");
duke@0 888 forward_ptr = obj->forwardee();
duke@0 889 }
duke@0 890 return forward_ptr;
duke@0 891 }
duke@0 892
duke@0 893 #ifdef ASSERT
duke@0 894 bool ParNewGeneration::is_legal_forward_ptr(oop p) {
duke@0 895 return
duke@0 896 (_avoid_promotion_undo && p == ClaimedForwardPtr)
duke@0 897 || Universe::heap()->is_in_reserved(p);
duke@0 898 }
duke@0 899 #endif
duke@0 900
duke@0 901 void ParNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) {
duke@0 902 if ((m != markOopDesc::prototype()) &&
duke@0 903 (!UseBiasedLocking || (m != markOopDesc::biased_locking_prototype()))) {
duke@0 904 MutexLocker ml(ParGCRareEvent_lock);
duke@0 905 DefNewGeneration::preserve_mark_if_necessary(obj, m);
duke@0 906 }
duke@0 907 }
duke@0 908
duke@0 909 // Multiple GC threads may try to promote an object. If the object
duke@0 910 // is successfully promoted, a forwarding pointer will be installed in
duke@0 911 // the object in the young generation. This method claims the right
duke@0 912 // to install the forwarding pointer before it copies the object,
duke@0 913 // thus avoiding the need to undo the copy as in
duke@0 914 // copy_to_survivor_space_avoiding_with_undo.
duke@0 915
duke@0 916 oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
duke@0 917 ParScanThreadState* par_scan_state, oop old, size_t sz, markOop m) {
duke@0 918 // In the sequential version, this assert also says that the object is
duke@0 919 // not forwarded. That might not be the case here. It is the case that
duke@0 920 // the caller observed it to be not forwarded at some time in the past.
duke@0 921 assert(is_in_reserved(old), "shouldn't be scavenging this oop");
duke@0 922
duke@0 923 // The sequential code read "old->age()" below. That doesn't work here,
duke@0 924 // since the age is in the mark word, and that might be overwritten with
duke@0 925 // a forwarding pointer by a parallel thread. So we must save the mark
duke@0 926 // word in a local and then analyze it.
duke@0 927 oopDesc dummyOld;
duke@0 928 dummyOld.set_mark(m);
duke@0 929 assert(!dummyOld.is_forwarded(),
duke@0 930 "should not be called with forwarding pointer mark word.");
duke@0 931
duke@0 932 oop new_obj = NULL;
duke@0 933 oop forward_ptr;
duke@0 934
duke@0 935 // Try allocating obj in to-space (unless too old)
duke@0 936 if (dummyOld.age() < tenuring_threshold()) {
duke@0 937 new_obj = (oop)par_scan_state->alloc_in_to_space(sz);
duke@0 938 if (new_obj == NULL) {
duke@0 939 set_survivor_overflow(true);
duke@0 940 }
duke@0 941 }
duke@0 942
duke@0 943 if (new_obj == NULL) {
duke@0 944 // Either to-space is full or we decided to promote
duke@0 945 // try allocating obj tenured
duke@0 946
duke@0 947 // Attempt to install a null forwarding pointer (atomically),
duke@0 948 // to claim the right to install the real forwarding pointer.
duke@0 949 forward_ptr = old->forward_to_atomic(ClaimedForwardPtr);
duke@0 950 if (forward_ptr != NULL) {
duke@0 951 // someone else beat us to it.
duke@0 952 return real_forwardee(old);
duke@0 953 }
duke@0 954
duke@0 955 new_obj = _next_gen->par_promote(par_scan_state->thread_num(),
duke@0 956 old, m, sz);
duke@0 957
duke@0 958 if (new_obj == NULL) {
duke@0 959 if (!HandlePromotionFailure) {
duke@0 960 // A failed promotion likely means the MaxLiveObjectEvacuationRatio flag
duke@0 961 // is incorrectly set. In any case, its seriously wrong to be here!
duke@0 962 vm_exit_out_of_memory(sz*wordSize, "promotion");
duke@0 963 }
duke@0 964 // promotion failed, forward to self
duke@0 965 _promotion_failed = true;
duke@0 966 new_obj = old;
duke@0 967
duke@0 968 preserve_mark_if_necessary(old, m);
duke@0 969 }
duke@0 970
duke@0 971 old->forward_to(new_obj);
duke@0 972 forward_ptr = NULL;
duke@0 973 } else {
duke@0 974 // Is in to-space; do copying ourselves.
duke@0 975 Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz);
duke@0 976 forward_ptr = old->forward_to_atomic(new_obj);
duke@0 977 // Restore the mark word copied above.
duke@0 978 new_obj->set_mark(m);
duke@0 979 // Increment age if obj still in new generation
duke@0 980 new_obj->incr_age();
duke@0 981 par_scan_state->age_table()->add(new_obj, sz);
duke@0 982 }
duke@0 983 assert(new_obj != NULL, "just checking");
duke@0 984
duke@0 985 if (forward_ptr == NULL) {
duke@0 986 oop obj_to_push = new_obj;
duke@0 987 if (par_scan_state->should_be_partially_scanned(obj_to_push, old)) {
duke@0 988 // Length field used as index of next element to be scanned.
duke@0 989 // Real length can be obtained from real_forwardee()
duke@0 990 arrayOop(old)->set_length(0);
duke@0 991 obj_to_push = old;
duke@0 992 assert(obj_to_push->is_forwarded() && obj_to_push->forwardee() != obj_to_push,
duke@0 993 "push forwarded object");
duke@0 994 }
duke@0 995 // Push it on one of the queues of to-be-scanned objects.
duke@0 996 if (!par_scan_state->work_queue()->push(obj_to_push)) {
duke@0 997 // Add stats for overflow pushes.
duke@0 998 if (Verbose && PrintGCDetails) {
duke@0 999 gclog_or_tty->print("queue overflow!\n");
duke@0 1000 }
duke@0 1001 push_on_overflow_list(old);
duke@0 1002 par_scan_state->note_overflow_push();
duke@0 1003 }
duke@0 1004 par_scan_state->note_push();
duke@0 1005
duke@0 1006 return new_obj;
duke@0 1007 }
duke@0 1008
duke@0 1009 // Oops. Someone beat us to it. Undo the allocation. Where did we
duke@0 1010 // allocate it?
duke@0 1011 if (is_in_reserved(new_obj)) {
duke@0 1012 // Must be in to_space.
duke@0 1013 assert(to()->is_in_reserved(new_obj), "Checking");
duke@0 1014 if (forward_ptr == ClaimedForwardPtr) {
duke@0 1015 // Wait to get the real forwarding pointer value.
duke@0 1016 forward_ptr = real_forwardee(old);
duke@0 1017 }
duke@0 1018 par_scan_state->undo_alloc_in_to_space((HeapWord*)new_obj, sz);
duke@0 1019 }
duke@0 1020
duke@0 1021 return forward_ptr;
duke@0 1022 }
duke@0 1023
duke@0 1024
duke@0 1025 // Multiple GC threads may try to promote the same object. If two
duke@0 1026 // or more GC threads copy the object, only one wins the race to install
duke@0 1027 // the forwarding pointer. The other threads have to undo their copy.
duke@0 1028
duke@0 1029 oop ParNewGeneration::copy_to_survivor_space_with_undo(
duke@0 1030 ParScanThreadState* par_scan_state, oop old, size_t sz, markOop m) {
duke@0 1031
duke@0 1032 // In the sequential version, this assert also says that the object is
duke@0 1033 // not forwarded. That might not be the case here. It is the case that
duke@0 1034 // the caller observed it to be not forwarded at some time in the past.
duke@0 1035 assert(is_in_reserved(old), "shouldn't be scavenging this oop");
duke@0 1036
duke@0 1037 // The sequential code read "old->age()" below. That doesn't work here,
duke@0 1038 // since the age is in the mark word, and that might be overwritten with
duke@0 1039 // a forwarding pointer by a parallel thread. So we must save the mark
duke@0 1040 // word here, install it in a local oopDesc, and then analyze it.
duke@0 1041 oopDesc dummyOld;
duke@0 1042 dummyOld.set_mark(m);
duke@0 1043 assert(!dummyOld.is_forwarded(),
duke@0 1044 "should not be called with forwarding pointer mark word.");
duke@0 1045
duke@0 1046 bool failed_to_promote = false;
duke@0 1047 oop new_obj = NULL;
duke@0 1048 oop forward_ptr;
duke@0 1049
duke@0 1050 // Try allocating obj in to-space (unless too old)
duke@0 1051 if (dummyOld.age() < tenuring_threshold()) {
duke@0 1052 new_obj = (oop)par_scan_state->alloc_in_to_space(sz);
duke@0 1053 if (new_obj == NULL) {
duke@0 1054 set_survivor_overflow(true);
duke@0 1055 }
duke@0 1056 }
duke@0 1057
duke@0 1058 if (new_obj == NULL) {
duke@0 1059 // Either to-space is full or we decided to promote
duke@0 1060 // try allocating obj tenured
duke@0 1061 new_obj = _next_gen->par_promote(par_scan_state->thread_num(),
duke@0 1062 old, m, sz);
duke@0 1063
duke@0 1064 if (new_obj == NULL) {
duke@0 1065 if (!HandlePromotionFailure) {
duke@0 1066 // A failed promotion likely means the MaxLiveObjectEvacuationRatio
duke@0 1067 // flag is incorrectly set. In any case, its seriously wrong to be
duke@0 1068 // here!
duke@0 1069 vm_exit_out_of_memory(sz*wordSize, "promotion");
duke@0 1070 }
duke@0 1071 // promotion failed, forward to self
duke@0 1072 forward_ptr = old->forward_to_atomic(old);
duke@0 1073 new_obj = old;
duke@0 1074
duke@0 1075 if (forward_ptr != NULL) {
duke@0 1076 return forward_ptr; // someone else succeeded
duke@0 1077 }
duke@0 1078
duke@0 1079 _promotion_failed = true;
duke@0 1080 failed_to_promote = true;
duke@0 1081
duke@0 1082 preserve_mark_if_necessary(old, m);
duke@0 1083 }
duke@0 1084 } else {
duke@0 1085 // Is in to-space; do copying ourselves.
duke@0 1086 Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz);
duke@0 1087 // Restore the mark word copied above.
duke@0 1088 new_obj->set_mark(m);
duke@0 1089 // Increment age if new_obj still in new generation
duke@0 1090 new_obj->incr_age();
duke@0 1091 par_scan_state->age_table()->add(new_obj, sz);
duke@0 1092 }
duke@0 1093 assert(new_obj != NULL, "just checking");
duke@0 1094
duke@0 1095 // Now attempt to install the forwarding pointer (atomically).
duke@0 1096 // We have to copy the mark word before overwriting with forwarding
duke@0 1097 // ptr, so we can restore it below in the copy.
duke@0 1098 if (!failed_to_promote) {
duke@0 1099 forward_ptr = old->forward_to_atomic(new_obj);
duke@0 1100 }
duke@0 1101
duke@0 1102 if (forward_ptr == NULL) {
duke@0 1103 oop obj_to_push = new_obj;
duke@0 1104 if (par_scan_state->should_be_partially_scanned(obj_to_push, old)) {
duke@0 1105 // Length field used as index of next element to be scanned.
duke@0 1106 // Real length can be obtained from real_forwardee()
duke@0 1107 arrayOop(old)->set_length(0);
duke@0 1108 obj_to_push = old;
duke@0 1109 assert(obj_to_push->is_forwarded() && obj_to_push->forwardee() != obj_to_push,
duke@0 1110 "push forwarded object");
duke@0 1111 }
duke@0 1112 // Push it on one of the queues of to-be-scanned objects.
duke@0 1113 if (!par_scan_state->work_queue()->push(obj_to_push)) {
duke@0 1114 // Add stats for overflow pushes.
duke@0 1115 push_on_overflow_list(old);
duke@0 1116 par_scan_state->note_overflow_push();
duke@0 1117 }
duke@0 1118 par_scan_state->note_push();
duke@0 1119
duke@0 1120 return new_obj;
duke@0 1121 }
duke@0 1122
duke@0 1123 // Oops. Someone beat us to it. Undo the allocation. Where did we
duke@0 1124 // allocate it?
duke@0 1125 if (is_in_reserved(new_obj)) {
duke@0 1126 // Must be in to_space.
duke@0 1127 assert(to()->is_in_reserved(new_obj), "Checking");
duke@0 1128 par_scan_state->undo_alloc_in_to_space((HeapWord*)new_obj, sz);
duke@0 1129 } else {
duke@0 1130 assert(!_avoid_promotion_undo, "Should not be here if avoiding.");
duke@0 1131 _next_gen->par_promote_alloc_undo(par_scan_state->thread_num(),
duke@0 1132 (HeapWord*)new_obj, sz);
duke@0 1133 }
duke@0 1134
duke@0 1135 return forward_ptr;
duke@0 1136 }
duke@0 1137
duke@0 1138 void ParNewGeneration::push_on_overflow_list(oop from_space_obj) {
duke@0 1139 oop cur_overflow_list = _overflow_list;
duke@0 1140 // if the object has been forwarded to itself, then we cannot
duke@0 1141 // use the klass pointer for the linked list. Instead we have
duke@0 1142 // to allocate an oopDesc in the C-Heap and use that for the linked list.
duke@0 1143 if (from_space_obj->forwardee() == from_space_obj) {
duke@0 1144 oopDesc* listhead = NEW_C_HEAP_ARRAY(oopDesc, 1);
duke@0 1145 listhead->forward_to(from_space_obj);
duke@0 1146 from_space_obj = listhead;
duke@0 1147 }
duke@0 1148 while (true) {
duke@0 1149 from_space_obj->set_klass_to_list_ptr(cur_overflow_list);
duke@0 1150 oop observed_overflow_list =
duke@0 1151 (oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list);
duke@0 1152 if (observed_overflow_list == cur_overflow_list) break;
duke@0 1153 // Otherwise...
duke@0 1154 cur_overflow_list = observed_overflow_list;
duke@0 1155 }
duke@0 1156 }
duke@0 1157
duke@0 1158 bool
duke@0 1159 ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) {
duke@0 1160 ObjToScanQueue* work_q = par_scan_state->work_queue();
duke@0 1161 // How many to take?
duke@0 1162 int objsFromOverflow = MIN2(work_q->max_elems()/4,
duke@0 1163 (juint)ParGCDesiredObjsFromOverflowList);
duke@0 1164
duke@0 1165 if (_overflow_list == NULL) return false;
duke@0 1166
duke@0 1167 // Otherwise, there was something there; try claiming the list.
duke@0 1168 oop prefix = (oop)Atomic::xchg_ptr(NULL, &_overflow_list);
duke@0 1169
duke@0 1170 if (prefix == NULL) {
duke@0 1171 return false;
duke@0 1172 }
duke@0 1173 // Trim off a prefix of at most objsFromOverflow items
duke@0 1174 int i = 1;
duke@0 1175 oop cur = prefix;
coleenp@167 1176 while (i < objsFromOverflow && cur->klass_or_null() != NULL) {
duke@0 1177 i++; cur = oop(cur->klass());
duke@0 1178 }
duke@0 1179
duke@0 1180 // Reattach remaining (suffix) to overflow list
coleenp@167 1181 if (cur->klass_or_null() != NULL) {
duke@0 1182 oop suffix = oop(cur->klass());
duke@0 1183 cur->set_klass_to_list_ptr(NULL);
duke@0 1184
duke@0 1185 // Find last item of suffix list
duke@0 1186 oop last = suffix;
coleenp@167 1187 while (last->klass_or_null() != NULL) {
duke@0 1188 last = oop(last->klass());
duke@0 1189 }
duke@0 1190 // Atomically prepend suffix to current overflow list
duke@0 1191 oop cur_overflow_list = _overflow_list;
duke@0 1192 while (true) {
duke@0 1193 last->set_klass_to_list_ptr(cur_overflow_list);
duke@0 1194 oop observed_overflow_list =
duke@0 1195 (oop)Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list);
duke@0 1196 if (observed_overflow_list == cur_overflow_list) break;
duke@0 1197 // Otherwise...
duke@0 1198 cur_overflow_list = observed_overflow_list;
duke@0 1199 }
duke@0 1200 }
duke@0 1201
duke@0 1202 // Push objects on prefix list onto this thread's work queue
duke@0 1203 assert(cur != NULL, "program logic");
duke@0 1204 cur = prefix;
duke@0 1205 int n = 0;
duke@0 1206 while (cur != NULL) {
duke@0 1207 oop obj_to_push = cur->forwardee();
duke@0 1208 oop next = oop(cur->klass());
duke@0 1209 cur->set_klass(obj_to_push->klass());
duke@0 1210 if (par_scan_state->should_be_partially_scanned(obj_to_push, cur)) {
duke@0 1211 obj_to_push = cur;
duke@0 1212 assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned");
duke@0 1213 }
duke@0 1214 work_q->push(obj_to_push);
duke@0 1215 cur = next;
duke@0 1216 n++;
duke@0 1217 }
duke@0 1218 par_scan_state->note_overflow_refill(n);
duke@0 1219 return true;
duke@0 1220 }
duke@0 1221
duke@0 1222 void ParNewGeneration::ref_processor_init()
duke@0 1223 {
duke@0 1224 if (_ref_processor == NULL) {
duke@0 1225 // Allocate and initialize a reference processor
duke@0 1226 _ref_processor = ReferenceProcessor::create_ref_processor(
duke@0 1227 _reserved, // span
duke@0 1228 refs_discovery_is_atomic(), // atomic_discovery
duke@0 1229 refs_discovery_is_mt(), // mt_discovery
duke@0 1230 NULL, // is_alive_non_header
duke@0 1231 ParallelGCThreads,
duke@0 1232 ParallelRefProcEnabled);
duke@0 1233 }
duke@0 1234 }
duke@0 1235
duke@0 1236 const char* ParNewGeneration::name() const {
duke@0 1237 return "par new generation";
duke@0 1238 }