Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8314935: Shenandoah: Unable to throw OOME on back-to-back Full GCs #15500

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -40,7 +40,8 @@ class ShenandoahCollectorPolicy : public CHeapObj<mtGC> {
private:
size_t _success_concurrent_gcs;
size_t _success_degenerated_gcs;
size_t _success_full_gcs;
// Written by control thread, read by mutators
volatile size_t _success_full_gcs;
size_t _alloc_failure_degenerated;
size_t _alloc_failure_degenerated_upgrade_to_full;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In GenShen tip, _alloc_failure_degenerated_upgrade_to_full is also declared volatile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_alloc_failure_degenerated_upgrade_to_full is only changed on a safepoint, so it shouldn't need any additional synchronization.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, as long as this resolves in genshen tip.

size_t _alloc_failure_full;
@@ -82,6 +83,10 @@ class ShenandoahCollectorPolicy : public CHeapObj<mtGC> {
size_t cycle_counter() const;

void print_gc_stats(outputStream* out) const;

size_t full_gc_count() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worthwhile to harmonize this with tip and rename to get_fullgc_count() ?
Unless the idea is to change genshen tip to use full_gc_count() like here when you pull these changes down.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with the style convention established by cycle_counter. I don't feel strongly about this. If you prefer get_full_gc_count, I can change that here (otherwise, I'll change genshen to use full_gc_count).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

full_gc_count is fine; so long as these eventually get resolved in genshen tip.

return _success_full_gcs + _alloc_failure_degenerated_upgrade_to_full;
}
};

#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCOLLECTORPOLICY_HPP
21 changes: 5 additions & 16 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
Original file line number Diff line number Diff line change
@@ -878,25 +878,14 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) {
// It might happen that one of the threads requesting allocation would unblock
// way later after GC happened, only to fail the second allocation, because
// other threads have already depleted the free storage. In this case, a better
// strategy is to try again, as long as GC makes progress.
//
// Then, we need to make sure the allocation was retried after at least one
// Full GC, which means we want to try more than ShenandoahFullGCThreshold times.

size_t tries = 0;

while (result == nullptr && _progress_last_gc.is_set()) {
tries++;
control_thread()->handle_alloc_failure(req);
result = allocate_memory_under_lock(req, in_new_region);
}

while (result == nullptr && tries <= ShenandoahFullGCThreshold) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to point out, the description of ShenandoahFullGCThreshold does not cover this use case (also, the original code here was not concerned with full GCs):

      "How many back-to-back Degenerated GCs should happen before going to a Full GC."

tries++;
// strategy is to try again, as long as GC makes progress (or until at least
// one full GC has completed).
size_t original_count = shenandoah_policy()->full_gc_count();
while (result == nullptr
&& (_progress_last_gc.is_set() || original_count == shenandoah_policy()->full_gc_count())) {
control_thread()->handle_alloc_failure(req);
result = allocate_memory_under_lock(req, in_new_region);
}

} else {
assert(req.is_gc_alloc(), "Can only accept GC allocs here");
result = allocate_memory_under_lock(req, in_new_region);