8335126: Shenandoah: Improve OOM handling
Reviewed-by: shade, ysr, wkemper, rkennke
This commit is contained in:
parent
284671a1e4
commit
3a87eb5c46
@ -318,7 +318,8 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau
|
|||||||
|
|
||||||
ShenandoahConcurrentGC gc;
|
ShenandoahConcurrentGC gc;
|
||||||
if (gc.collect(cause)) {
|
if (gc.collect(cause)) {
|
||||||
// Cycle is complete
|
// Cycle is complete. There were no failed allocation requests and no degeneration, so count this as good progress.
|
||||||
|
heap->notify_gc_progress();
|
||||||
heap->heuristics()->record_success_concurrent();
|
heap->heuristics()->record_success_concurrent();
|
||||||
heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated());
|
heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated());
|
||||||
} else {
|
} else {
|
||||||
|
@ -228,7 +228,6 @@ void ShenandoahDegenGC::op_degenerated() {
|
|||||||
// Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles,
|
// Check for futility and fail. There is no reason to do several back-to-back Degenerated cycles,
|
||||||
// because that probably means the heap is overloaded and/or fragmented.
|
// because that probably means the heap is overloaded and/or fragmented.
|
||||||
if (!metrics.is_good_progress()) {
|
if (!metrics.is_good_progress()) {
|
||||||
heap->notify_gc_no_progress();
|
|
||||||
heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc);
|
heap->cancel_gc(GCCause::_shenandoah_upgrade_to_full_gc);
|
||||||
op_degenerated_futile();
|
op_degenerated_futile();
|
||||||
} else {
|
} else {
|
||||||
|
@ -945,24 +945,36 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block until control thread reacted, then retry allocation.
|
if (result == nullptr) {
|
||||||
//
|
// Block until control thread reacted, then retry allocation.
|
||||||
// It might happen that one of the threads requesting allocation would unblock
|
//
|
||||||
// way later after GC happened, only to fail the second allocation, because
|
// It might happen that one of the threads requesting allocation would unblock
|
||||||
// other threads have already depleted the free storage. In this case, a better
|
// way later after GC happened, only to fail the second allocation, because
|
||||||
// strategy is to try again, as long as GC makes progress (or until at least
|
// other threads have already depleted the free storage. In this case, a better
|
||||||
// one full GC has completed).
|
// strategy is to try again, until at least one full GC has completed.
|
||||||
size_t original_count = shenandoah_policy()->full_gc_count();
|
//
|
||||||
while (result == nullptr
|
// Stop retrying and return nullptr to cause OOMError exception if our allocation failed even after:
|
||||||
&& (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) {
|
// a) We experienced a GC that had good progress, or
|
||||||
control_thread()->handle_alloc_failure(req, true);
|
// b) We experienced at least one Full GC (whether or not it had good progress)
|
||||||
result = allocate_memory_under_lock(req, in_new_region);
|
//
|
||||||
}
|
// TODO: Consider GLOBAL GC rather than Full GC to remediate OOM condition: https://bugs.openjdk.org/browse/JDK-8335910
|
||||||
|
|
||||||
if (log_is_enabled(Debug, gc, alloc)) {
|
size_t original_count = shenandoah_policy()->full_gc_count();
|
||||||
ResourceMark rm;
|
while ((result == nullptr) && (original_count == shenandoah_policy()->full_gc_count())) {
|
||||||
log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT ", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT,
|
control_thread()->handle_alloc_failure(req, true);
|
||||||
Thread::current()->name(), p2i(result), req.type_string(), req.size(), original_count, get_gc_no_progress_count());
|
result = allocate_memory_under_lock(req, in_new_region);
|
||||||
|
}
|
||||||
|
if (result != nullptr) {
|
||||||
|
// If our allocation request has been satisifed after it initially failed, we count this as good gc progress
|
||||||
|
notify_gc_progress();
|
||||||
|
}
|
||||||
|
if (log_is_enabled(Debug, gc, alloc)) {
|
||||||
|
ResourceMark rm;
|
||||||
|
log_debug(gc, alloc)("Thread: %s, Result: " PTR_FORMAT ", Request: %s, Size: " SIZE_FORMAT
|
||||||
|
", Original: " SIZE_FORMAT ", Latest: " SIZE_FORMAT,
|
||||||
|
Thread::current()->name(), p2i(result), req.type_string(), req.size(),
|
||||||
|
original_count, get_gc_no_progress_count());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(req.is_gc_alloc(), "Can only accept GC allocs here");
|
assert(req.is_gc_alloc(), "Can only accept GC allocs here");
|
||||||
|
Loading…
Reference in New Issue
Block a user