// VM operation to invoke a concurrent collection of a // GenCollectedHeap heap. void VM_GenCollectFullConcurrent::doit() { assert(Thread::current()->is_VM_thread(), "Should be VM thread"); assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected"); GenCollectedHeap* gch = GenCollectedHeap::heap(); if (_gc_count_before == gch->total_collections()) { // The "full" of do_full_collection call below "forces" // a collection; the second arg, 0, below ensures that // only the young gen is collected. XXX In the future, // we'll probably need to have something in this interface // to say do this only if we are sure we will not bail // out to a full collection in this attempt, but that's // for the future. assert(SafepointSynchronize::is_at_safepoint(), "We can only be executing this arm of if at a safepoint"); GCCauseSetter gccs(gch, _gc_cause); gch->do_full_collection(gch->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen); } // Else no need for a foreground young gc assert((_gc_count_before < gch->total_collections()) || (GCLocker::is_active() /* gc may have been skipped */ && (_gc_count_before == gch->total_collections())), "total_collections() should be monotonically increasing"); MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); assert(_full_gc_count_before <= gch->total_full_collections(), "Error"); if (gch->total_full_collections() == _full_gc_count_before) { // Nudge the CMS thread to start a concurrent collection. CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); } else { assert(_full_gc_count_before < gch->total_full_collections(), "Error"); FullGCCount_lock->notify_all(); // Inform the Java thread its work is done } }
bool VM_GenCollectFullConcurrent::evaluate_at_safepoint() const { Thread* thr = Thread::current(); assert(thr != NULL, "Unexpected tid"); if (!thr->is_Java_thread()) { assert(thr->is_VM_thread(), "Expected to be evaluated by VM thread"); GenCollectedHeap* gch = GenCollectedHeap::heap(); if (_gc_count_before != gch->total_collections()) { // No need to do a young gc, we'll just nudge the CMS thread // in the doit() method above, to be executed soon. assert(_gc_count_before < gch->total_collections(), "total_collections() should be monotonically increasing"); return false; // no need for foreground young gc } } return true; // may still need foreground young gc }
// Wait until the next synchronous GC, a concurrent full gc request, // or a timeout, whichever is earlier. void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { // Wait time in millis or 0 value representing infinite wait for a scavenge assert(t_millis >= 0, "Wait time for scavenge should be 0 or positive"); GenCollectedHeap* gch = GenCollectedHeap::heap(); double start_time_secs = os::elapsedTime(); double end_time_secs = start_time_secs + (t_millis / ((double) MILLIUNITS)); // Total collections count before waiting loop unsigned int before_count; { MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); before_count = gch->total_collections(); } unsigned int loop_count = 0; while(!_should_terminate) { double now_time = os::elapsedTime(); long wait_time_millis; if(t_millis != 0) { // New wait limit wait_time_millis = (long) ((end_time_secs - now_time) * MILLIUNITS); if(wait_time_millis <= 0) { // Wait time is over break; } } else { // No wait limit, wait if necessary forever wait_time_millis = 0; } // Wait until the next event or the remaining timeout { MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); if (_should_terminate || _collector->_full_gc_requested) { return; } set_CMS_flag(CMS_cms_wants_token); // to provoke notifies assert(t_millis == 0 || wait_time_millis > 0, "Sanity"); CGC_lock->wait(Mutex::_no_safepoint_check_flag, wait_time_millis); clear_CMS_flag(CMS_cms_wants_token); assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token), "Should not be set"); } // Extra wait time check before entering the heap lock to get the collection count if(t_millis != 0 && os::elapsedTime() >= end_time_secs) { // Wait time is over break; } // Total collections count after the event unsigned int after_count; { MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); after_count = gch->total_collections(); } if(before_count != after_count) { // There was a collection - success break; } // Too many loops warning if(++loop_count == 0) { warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1); } } }
void ASParNewGeneration::resize_spaces(size_t requested_eden_size, size_t requested_survivor_size) { assert(UseAdaptiveSizePolicy, "sanity check"); assert(requested_eden_size > 0 && requested_survivor_size > 0, "just checking"); CollectedHeap* heap = Universe::heap(); assert(heap->kind() == CollectedHeap::GenCollectedHeap, "Sanity"); // We require eden and to space to be empty if ((!eden()->is_empty()) || (!to()->is_empty())) { return; } size_t cur_eden_size = eden()->capacity(); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr("ASParNew::resize_spaces(requested_eden_size: " SIZE_FORMAT ", requested_survivor_size: " SIZE_FORMAT ")", requested_eden_size, requested_survivor_size); gclog_or_tty->print_cr(" eden: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, eden()->bottom(), eden()->end(), pointer_delta(eden()->end(), eden()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" from: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, from()->bottom(), from()->end(), pointer_delta(from()->end(), from()->bottom(), sizeof(char))); gclog_or_tty->print_cr(" to: [" PTR_FORMAT ".." PTR_FORMAT ") " SIZE_FORMAT, to()->bottom(), to()->end(), pointer_delta( to()->end(), to()->bottom(), sizeof(char))); } // There's nothing to do if the new sizes are the same as the current if (requested_survivor_size == to()->capacity() && requested_survivor_size == from()->capacity() && requested_eden_size == eden()->capacity()) { if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" capacities are the right sizes, returning"); } return; } char* eden_start = (char*)eden()->bottom(); char* eden_end = (char*)eden()->end(); char* from_start = (char*)from()->bottom(); char* from_end = (char*)from()->end(); char* to_start = (char*)to()->bottom(); char* to_end = (char*)to()->end(); const size_t alignment = os::vm_page_size(); const bool maintain_minimum = (requested_eden_size + 2 * requested_survivor_size) <= min_gen_size(); // Check whether from space is below to space if (from_start < to_start) { // Eden, from, to if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, from, to:"); } // Set eden // "requested_eden_size" is a goal for the size of eden // and may not be attainable. "eden_size" below is // calculated based on the location of from-space and // the goal for the size of eden. from-space is // fixed in place because it contains live data. // The calculation is done this way to avoid 32bit // overflow (i.e., eden_start + requested_eden_size // may too large for representation in 32bits). size_t eden_size; if (maintain_minimum) { // Only make eden larger than the requested size if // the minimum size of the generation has to be maintained. // This could be done in general but policy at a higher // level is determining a requested size for eden and that // should be honored unless there is a fundamental reason. eden_size = pointer_delta(from_start, eden_start, sizeof(char)); } else { eden_size = MIN2(requested_eden_size, pointer_delta(from_start, eden_start, sizeof(char))); } eden_size = align_size_down(eden_size, alignment); eden_end = eden_start + eden_size; assert(eden_end >= eden_start, "addition overflowed") // To may resize into from space as long as it is clear of live data. // From space must remain page aligned, though, so we need to do some // extra calculations. // First calculate an optimal to-space to_end = (char*)virtual_space()->high(); to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size, sizeof(char)); // Does the optimal to-space overlap from-space? if (to_start < (char*)from()->end()) { // Calculate the minimum offset possible for from_end size_t from_size = pointer_delta(from()->top(), from_start, sizeof(char)); // Should we be in this method if from_space is empty? Why not the set_space method? FIX ME! if (from_size == 0) { from_size = alignment; } else { from_size = align_size_up(from_size, alignment); } from_end = from_start + from_size; assert(from_end > from_start, "addition overflow or from_size problem"); guarantee(from_end <= (char*)from()->end(), "from_end moved to the right"); // Now update to_start with the new from_end to_start = MAX2(from_end, to_start); } else { // If shrinking, move to-space down to abut the end of from-space // so that shrinking will move to-space down. If not shrinking // to-space is moving up to allow for growth on the next expansion. if (requested_eden_size <= cur_eden_size) { to_start = from_end; if (to_start + requested_survivor_size > to_start) { to_end = to_start + requested_survivor_size; } } // else leave to_end pointing to the high end of the virtual space. } guarantee(to_start != to_end, "to space is zero sized"); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); } } else { // Eden, to, from if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" Eden, to, from:"); } // Calculate the to-space boundaries based on // the start of from-space. to_end = from_start; to_start = (char*)pointer_delta(from_start, (char*)requested_survivor_size, sizeof(char)); // Calculate the ideal eden boundaries. // eden_end is already at the bottom of the generation assert(eden_start == virtual_space()->low(), "Eden is not starting at the low end of the virtual space"); if (eden_start + requested_eden_size >= eden_start) { eden_end = eden_start + requested_eden_size; } else { eden_end = to_start; } // Does eden intrude into to-space? to-space // gets priority but eden is not allowed to shrink // to 0. if (eden_end > to_start) { eden_end = to_start; } // Don't let eden shrink down to 0 or less. eden_end = MAX2(eden_end, eden_start + alignment); assert(eden_start + alignment >= eden_start, "Overflow"); size_t eden_size; if (maintain_minimum) { // Use all the space available. eden_end = MAX2(eden_end, to_start); eden_size = pointer_delta(eden_end, eden_start, sizeof(char)); eden_size = MIN2(eden_size, cur_eden_size); } else { eden_size = pointer_delta(eden_end, eden_start, sizeof(char)); } eden_size = align_size_down(eden_size, alignment); assert(maintain_minimum || eden_size <= requested_eden_size, "Eden size is too large"); assert(eden_size >= alignment, "Eden size is too small"); eden_end = eden_start + eden_size; // Move to-space down to eden. if (requested_eden_size < cur_eden_size) { to_start = eden_end; if (to_start + requested_survivor_size > to_start) { to_end = MIN2(from_start, to_start + requested_survivor_size); } else { to_end = from_start; } } // eden_end may have moved so again make sure // the to-space and eden don't overlap. to_start = MAX2(eden_end, to_start); // from-space size_t from_used = from()->used(); if (requested_survivor_size > from_used) { if (from_start + requested_survivor_size >= from_start) { from_end = from_start + requested_survivor_size; } if (from_end > virtual_space()->high()) { from_end = virtual_space()->high(); } } assert(to_start >= eden_end, "to-space should be above eden"); if (PrintAdaptiveSizePolicy && Verbose) { gclog_or_tty->print_cr(" [eden_start .. eden_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, eden_start, eden_end, pointer_delta(eden_end, eden_start, sizeof(char))); gclog_or_tty->print_cr(" [ to_start .. to_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, to_start, to_end, pointer_delta( to_end, to_start, sizeof(char))); gclog_or_tty->print_cr(" [from_start .. from_end): " "[" PTR_FORMAT " .. " PTR_FORMAT ") " SIZE_FORMAT, from_start, from_end, pointer_delta(from_end, from_start, sizeof(char))); } } guarantee((HeapWord*)from_start <= from()->bottom(), "from start moved to the right"); guarantee((HeapWord*)from_end >= from()->top(), "from end moved into live data"); assert(is_object_aligned((intptr_t)eden_start), "checking alignment"); assert(is_object_aligned((intptr_t)from_start), "checking alignment"); assert(is_object_aligned((intptr_t)to_start), "checking alignment"); MemRegion edenMR((HeapWord*)eden_start, (HeapWord*)eden_end); MemRegion toMR ((HeapWord*)to_start, (HeapWord*)to_end); MemRegion fromMR((HeapWord*)from_start, (HeapWord*)from_end); // Let's make sure the call to initialize doesn't reset "top"! HeapWord* old_from_top = from()->top(); // For PrintAdaptiveSizePolicy block below size_t old_from = from()->capacity(); size_t old_to = to()->capacity(); // If not clearing the spaces, do some checking to verify that // the spaces are already mangled. // Must check mangling before the spaces are reshaped. Otherwise, // the bottom or end of one space may have moved into another // a failure of the check may not correctly indicate which space // is not properly mangled. if (ZapUnusedHeapArea) { HeapWord* limit = (HeapWord*) virtual_space()->high(); eden()->check_mangled_unused_area(limit); from()->check_mangled_unused_area(limit); to()->check_mangled_unused_area(limit); } // The call to initialize NULL's the next compaction space eden()->initialize(edenMR, SpaceDecorator::Clear, SpaceDecorator::DontMangle); eden()->set_next_compaction_space(from()); to()->initialize(toMR , SpaceDecorator::Clear, SpaceDecorator::DontMangle); from()->initialize(fromMR, SpaceDecorator::DontClear, SpaceDecorator::DontMangle); assert(from()->top() == old_from_top, "from top changed!"); if (PrintAdaptiveSizePolicy) { GenCollectedHeap* gch = GenCollectedHeap::heap(); assert(gch->kind() == CollectedHeap::GenCollectedHeap, "Sanity"); gclog_or_tty->print("AdaptiveSizePolicy::survivor space sizes: " "collection: %d " "(" SIZE_FORMAT ", " SIZE_FORMAT ") -> " "(" SIZE_FORMAT ", " SIZE_FORMAT ") ", gch->total_collections(), old_from, old_to, from()->capacity(), to()->capacity()); gclog_or_tty->cr(); } }
HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, bool is_tlab, bool* gc_overhead_limit_was_exceeded) { GenCollectedHeap *gch = GenCollectedHeap::heap(); debug_only(gch->check_for_valid_allocation_state()); assert(gch->no_gc_in_progress(), "Allocation during gc not allowed"); // In general gc_overhead_limit_was_exceeded should be false so // set it so here and reset it to true only if the gc time // limit is being exceeded as checked below. *gc_overhead_limit_was_exceeded = false; HeapWord* result = NULL; // Loop until the allocation is satisfied, or unsatisfied after GC. for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { HandleMark hm; // Discard any handles allocated in each iteration. // First allocation attempt is lock-free. Generation *young = gch->young_gen(); assert(young->supports_inline_contig_alloc(), "Otherwise, must do alloc within heap lock"); if (young->should_allocate(size, is_tlab)) { result = young->par_allocate(size, is_tlab); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } } uint gc_count_before; // Read inside the Heap_lock locked region. { MutexLocker ml(Heap_lock); log_trace(gc, alloc)("GenCollectorPolicy::mem_allocate_work: attempting locked slow path allocation"); // Note that only large objects get a shot at being // allocated in later generations. bool first_only = ! should_try_older_generation_allocation(size); result = gch->attempt_allocation(size, is_tlab, first_only); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } if (GCLocker::is_active_and_needs_gc()) { if (is_tlab) { return NULL; // Caller will retry allocating individual object. } if (!gch->is_maximal_no_gc()) { // Try and expand heap to satisfy request. result = expand_heap_and_allocate(size, is_tlab); // Result could be null if we are out of space. if (result != NULL) { return result; } } if (gclocker_stalled_count > GCLockerRetryAllocationCount) { return NULL; // We didn't get to do a GC and we didn't get any memory. } // If this thread is not in a jni critical section, we stall // the requestor until the critical section has cleared and // GC allowed. When the critical section clears, a GC is // initiated by the last thread exiting the critical section; so // we retry the allocation sequence from the beginning of the loop, // rather than causing more, now probably unnecessary, GC attempts. JavaThread* jthr = JavaThread::current(); if (!jthr->in_critical()) { MutexUnlocker mul(Heap_lock); // Wait for JNI critical section to be exited GCLocker::stall_until_clear(); gclocker_stalled_count += 1; continue; } else { if (CheckJNICalls) { fatal("Possible deadlock due to allocating while" " in jni critical section"); } return NULL; } } // Read the gc count while the heap lock is held. gc_count_before = gch->total_collections(); } VM_GenCollectForAllocation op(size, is_tlab, gc_count_before); VMThread::execute(&op); if (op.prologue_succeeded()) { result = op.result(); if (op.gc_locked()) { assert(result == NULL, "must be NULL if gc_locked() is true"); continue; // Retry and/or stall as necessary. } // Allocation has failed and a collection // has been done. If the gc time limit was exceeded the // this time, return NULL so that an out-of-memory // will be thrown. Clear gc_overhead_limit_exceeded // so that the overhead exceeded does not persist. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = all_soft_refs_clear(); if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); if (op.result() != NULL) { CollectedHeap::fill_with_object(op.result(), size); } return NULL; } assert(result == NULL || gch->is_in_reserved(result), "result not in heap"); return result; } // Give a warning if we seem to be looping forever. if ((QueuedAllocationWarningCount > 0) && (try_count % QueuedAllocationWarningCount == 0)) { log_warning(gc, ergo)("GenCollectorPolicy::mem_allocate_work retries %d times," " size=" SIZE_FORMAT " %s", try_count, size, is_tlab ? "(TLAB)" : ""); } } }