// Basic allocation policy. Should never be called at a safepoint, or // from the VM thread. // // This method must handle cases where many mem_allocate requests fail // simultaneously. When that happens, only one VM operation will succeed, // and the rest will not be executed. For that reason, this method loops // during failed allocation attempts. If the java heap becomes exhausted, // we rely on the size_policy object to force a bail out. HeapWord* ParallelScavengeHeap::mem_allocate( size_t size, bool is_noref, bool is_tlab, bool* gc_overhead_limit_was_exceeded) { assert(!SafepointSynchronize::is_at_safepoint(), "should not be at safepoint"); assert(Thread::current() != (Thread*)VMThread::vm_thread(), "should not be in vm thread"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); // 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 = young_gen()->allocate(size, is_tlab); uint loop_count = 0; uint gc_count = 0; while (result == NULL) { // We don't want to have multiple collections for a single filled generation. // To prevent this, each thread tracks the total_collections() value, and if // the count has changed, does not do a new collection. // // The collection count must be read only while holding the heap lock. VM // operations also hold the heap lock during collections. There is a lock // contention case where thread A blocks waiting on the Heap_lock, while // thread B is holding it doing a collection. When thread A gets the lock, // the collection count has already changed. To prevent duplicate collections, // The policy MUST attempt allocations during the same period it reads the // total_collections() value! { MutexLocker ml(Heap_lock); gc_count = Universe::heap()->total_collections(); result = young_gen()->allocate(size, is_tlab); // (1) If the requested object is too large to easily fit in the // young_gen, or // (2) If GC is locked out via GCLocker, young gen is full and // the need for a GC already signalled to GCLocker (done // at a safepoint), // ... then, rather than force a safepoint and (a potentially futile) // collection (attempt) for each allocation, try allocation directly // in old_gen. For case (2) above, we may in the future allow // TLAB allocation directly in the old gen. if (result != NULL) { return result; } if (!is_tlab && size >= (young_gen()->eden_space()->capacity_in_words(Thread::current()) / 2)) { result = old_gen()->allocate(size, is_tlab); if (result != NULL) { return result; } } if (GC_locker::is_active_and_needs_gc()) { // GC is locked out. If this is a TLAB allocation, // return NULL; the requestor will retry allocation // of an idividual object at a time. if (is_tlab) { return NULL; } // 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); GC_locker::stall_until_clear(); continue; } else { if (CheckJNICalls) { fatal("Possible deadlock due to allocating while" " in jni critical section"); } return NULL; } } } if (result == NULL) { // Generate a VM operation VM_ParallelGCFailedAllocation op(size, is_tlab, gc_count); VMThread::execute(&op); // Did the VM operation execute? If so, return the result directly. // This prevents us from looping until time out on requests that can // not be satisfied. if (op.prologue_succeeded()) { assert(Universe::heap()->is_in_or_null(op.result()), "result not in heap"); // If GC was locked out during VM operation then retry allocation // and/or stall as necessary. if (op.gc_locked()) { assert(op.result() == NULL, "must be NULL if gc_locked() is true"); continue; // retry and/or stall as necessary } // Exit the loop if the gc time limit has been exceeded. // The allocation must have failed above ("result" guarding // this path is NULL) and the most recent collection has exceeded the // gc overhead limit (although enough may have been collected to // satisfy the allocation). Exit the loop so that an out-of-memory // will be thrown (return a NULL ignoring the contents of // op.result()), // but clear gc_overhead_limit_exceeded so that the next collection // starts with a clean slate (i.e., forgets about previous overhead // excesses). Fill op.result() with a filler object so that the // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("ParallelScavengeHeap::mem_allocate: " "return NULL because gc_overhead_limit_exceeded is set"); } if (op.result() != NULL) { CollectedHeap::fill_with_object(op.result(), size); } return NULL; } return op.result(); } } // The policy object will prevent us from looping forever. If the // time spent in gc crosses a threshold, we will bail out. loop_count++; if ((result == NULL) && (QueuedAllocationWarningCount > 0) && (loop_count % QueuedAllocationWarningCount == 0)) { warning("ParallelScavengeHeap::mem_allocate retries %d times \n\t" " size=%d %s", loop_count, size, is_tlab ? "(TLAB)" : ""); } } return result; }
// Basic allocation policy. Should never be called at a safepoint, or // from the VM thread. // // This method must handle cases where many mem_allocate requests fail // simultaneously. When that happens, only one VM operation will succeed, // and the rest will not be executed. For that reason, this method loops // during failed allocation attempts. If the java heap becomes exhausted, // we rely on the size_policy object to force a bail out. HeapWord* ParallelScavengeHeap::mem_allocate( size_t size, bool* gc_overhead_limit_was_exceeded) { assert(!SafepointSynchronize::is_at_safepoint(), "should not be at safepoint"); assert(Thread::current() != (Thread*)VMThread::vm_thread(), "should not be in vm thread"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); // 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 = young_gen()->allocate(size); uint loop_count = 0; uint gc_count = 0; uint gclocker_stalled_count = 0; while (result == NULL) { // We don't want to have multiple collections for a single filled generation. // To prevent this, each thread tracks the total_collections() value, and if // the count has changed, does not do a new collection. // // The collection count must be read only while holding the heap lock. VM // operations also hold the heap lock during collections. There is a lock // contention case where thread A blocks waiting on the Heap_lock, while // thread B is holding it doing a collection. When thread A gets the lock, // the collection count has already changed. To prevent duplicate collections, // The policy MUST attempt allocations during the same period it reads the // total_collections() value! { MutexLocker ml(Heap_lock); gc_count = total_collections(); result = young_gen()->allocate(size); if (result != NULL) { return result; } // If certain conditions hold, try allocating from the old gen. result = mem_allocate_old_gen(size); if (result != NULL) { return result; } if (gclocker_stalled_count > GCLockerRetryAllocationCount) { return NULL; } // Failed to allocate without a gc. if (GCLocker::is_active_and_needs_gc()) { // 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); 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; } } } if (result == NULL) { // Generate a VM operation VM_ParallelGCFailedAllocation op(size, gc_count); VMThread::execute(&op); // Did the VM operation execute? If so, return the result directly. // This prevents us from looping until time out on requests that can // not be satisfied. if (op.prologue_succeeded()) { assert(is_in_or_null(op.result()), "result not in heap"); // If GC was locked out during VM operation then retry allocation // and/or stall as necessary. if (op.gc_locked()) { assert(op.result() == NULL, "must be NULL if gc_locked() is true"); continue; // retry and/or stall as necessary } // Exit the loop if the gc time limit has been exceeded. // The allocation must have failed above ("result" guarding // this path is NULL) and the most recent collection has exceeded the // gc overhead limit (although enough may have been collected to // satisfy the allocation). Exit the loop so that an out-of-memory // will be thrown (return a NULL ignoring the contents of // op.result()), // but clear gc_overhead_limit_exceeded so that the next collection // starts with a clean slate (i.e., forgets about previous overhead // excesses). Fill op.result() with a filler object so that the // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); log_trace(gc)("ParallelScavengeHeap::mem_allocate: return NULL because gc_overhead_limit_exceeded is set"); if (op.result() != NULL) { CollectedHeap::fill_with_object(op.result(), size); } return NULL; } return op.result(); } } // The policy object will prevent us from looping forever. If the // time spent in gc crosses a threshold, we will bail out. loop_count++; if ((result == NULL) && (QueuedAllocationWarningCount > 0) && (loop_count % QueuedAllocationWarningCount == 0)) { log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count); log_warning(gc)("\tsize=" SIZE_FORMAT, size); } } return result; }