Skip to content
Closed
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
702710e
Improve documentation of how Evac-OOM Protocol works
kdnilsen Jan 12, 2024
61b575f
Merge branch 'openjdk:master' into master
kdnilsen Jan 17, 2024
51d056f
Revert "Improve documentation of how Evac-OOM Protocol works"
kdnilsen Jan 17, 2024
ba98e42
Merge branch 'openjdk:master' into master
kdnilsen Jan 23, 2024
441487c
Merge branch 'openjdk:master' into master
kdnilsen Jan 25, 2024
dafc363
Merge branch 'openjdk:master' into master
kdnilsen Feb 2, 2024
c4c252e
Merge branch 'openjdk:master' into master
kdnilsen Feb 21, 2024
41ba86a
Merge branch 'openjdk:master' into master
kdnilsen Feb 28, 2024
f215a70
Merge branch 'openjdk:master' into master
kdnilsen Mar 1, 2024
4d6b5cd
Merge branch 'openjdk:master' into master
kdnilsen Mar 26, 2024
7fe605f
Merge branch 'openjdk:master' into master
kdnilsen Mar 28, 2024
2e224f6
Merge branch 'openjdk:master' into master
kdnilsen Apr 30, 2024
46ad5c6
Merge branch 'openjdk:master' into master
kdnilsen May 3, 2024
9a1989d
Merge branch 'openjdk:master' into master
kdnilsen May 9, 2024
4126c22
Merge branch 'openjdk:master' into master
kdnilsen Jun 12, 2024
981692e
Merge branch 'openjdk:master' into master
kdnilsen Jun 14, 2024
3a67b1f
Make GC logging less verbose
kdnilsen Jun 14, 2024
3692312
Revert "Make GC logging less verbose"
kdnilsen Jun 19, 2024
045590b
Merge branch 'openjdk:master' into master
kdnilsen Jun 26, 2024
fbbd88c
Merge branch 'openjdk:master' into master
kdnilsen Jul 8, 2024
7e0edf0
Merge branch 'openjdk:master' into master
kdnilsen Sep 12, 2024
3525369
Merge branch 'openjdk:master' into master
kdnilsen Sep 26, 2024
fe0da51
Merge branch 'openjdk:master' into master
kdnilsen Nov 6, 2024
db12fe5
Merge branch 'openjdk:master' into master
kdnilsen Dec 6, 2024
0440bae
Merge branch 'openjdk:master' into master
kdnilsen Jan 16, 2025
3bdc022
Merge branch 'openjdk:master' into master
kdnilsen Jan 19, 2025
1ee2ff1
Merge branch 'openjdk:master' into master
kdnilsen Feb 7, 2025
e6e772f
Merge branch 'openjdk:master' into master
kdnilsen Feb 27, 2025
c5a159e
Merge branch 'openjdk:master' into master
kdnilsen Mar 18, 2025
e7ca4f8
Merge branch 'openjdk:master' into master
kdnilsen Mar 20, 2025
42a93c7
Merge branch 'openjdk:master' into master
kdnilsen Mar 27, 2025
3841ca6
Merge branch 'openjdk:master' into master
kdnilsen Apr 8, 2025
9386e90
Merge branch 'openjdk:master' into master
kdnilsen Apr 10, 2025
0252a5c
Merge branch 'openjdk:master' into master
kdnilsen Apr 22, 2025
e029b8c
Merge branch 'openjdk:master' into master
kdnilsen May 8, 2025
72ad42e
Merge branch 'openjdk:master' into master
kdnilsen Jun 12, 2025
7a20ef2
Merge branch 'openjdk:master' into master
kdnilsen Jun 30, 2025
49f8589
Changes to track evacuation
kdnilsen Jun 30, 2025
ef668c8
filter pip regions at 30% min usage
kdnilsen Jun 30, 2025
1ea9b3e
do not promote primitive humongous arrays
kdnilsen Jun 30, 2025
d9170a1
Less aggressive compaction of old
kdnilsen Jun 30, 2025
bc28a38
Only defragment old if non-zero humongous reserve
kdnilsen Jun 30, 2025
578b240
Merge branch 'openjdk:master' into master
kdnilsen Jul 7, 2025
9b076f7
Merge remote-tracking branch 'jdk/master' into combined-evac-improvem…
kdnilsen Jul 16, 2025
02a47e6
Merge remote-tracking branch 'jdk/master' into combined-evac-improvem…
kdnilsen Jul 16, 2025
dfd24cc
manualy resolve evac tracker diffs
kdnilsen Jul 16, 2025
d46ece0
Merge branch 'openjdk:master' into master
kdnilsen Jul 29, 2025
e134bbf
Merge branch 'openjdk:master' into master
kdnilsen Aug 28, 2025
6b1ddc1
Merge remote-tracking branch 'origin/master' into combined-evac-impro…
kdnilsen Sep 15, 2025
6fc458a
Merge remote-tracking branch 'jdk/master' into combined-evac-improvem…
kdnilsen Sep 15, 2025
69a7600
Respond to reviewer feedback
kdnilsen Sep 15, 2025
1ff5149
revert changes to trash_humongous_region_at()
kdnilsen Sep 16, 2025
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
Expand Up @@ -412,7 +412,7 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
size_t defrag_count = 0;
size_t total_uncollected_old_regions = _last_old_region - _last_old_collection_candidate;

if (cand_idx > _last_old_collection_candidate) {
if ((ShenandoahGenerationalHumongousReserve > 0) && (cand_idx > _last_old_collection_candidate)) {
// Above, we have added into the set of mixed-evacuation candidates all old-gen regions for which the live memory
// that they contain is below a particular old-garbage threshold. Regions that were not selected for the collection
// set hold enough live memory that it is not considered efficient (by "garbage-first standards") to compact these
Expand Down
10 changes: 5 additions & 5 deletions src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) {

const size_t old_garbage_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahOldGarbageThreshold) / 100;

const size_t pip_used_threshold = (ShenandoahHeapRegion::region_size_bytes() * ShenandoahGenerationalMinPIPUsage) / 100;

size_t old_consumed = 0;
size_t promo_potential = 0;
size_t candidates = 0;
Expand All @@ -557,10 +559,8 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) {
continue;
}
if (heap->is_tenurable(r)) {
if ((r->garbage() < old_garbage_threshold)) {
// This tenure-worthy region has too little garbage, so we do not want to expend the copying effort to
// reclaim the garbage; instead this region may be eligible for promotion-in-place to the
// old generation.
if ((r->garbage() < old_garbage_threshold) && (r->used() > pip_used_threshold)) {
// We prefer to promote this region in place because is has a small amount of garbage and a large usage.
HeapWord* tams = ctx->top_at_mark_start(r);
HeapWord* original_top = r->top();
if (!heap->is_concurrent_old_mark_in_progress() && tams == original_top) {
Expand All @@ -586,7 +586,7 @@ size_t ShenandoahGeneration::select_aged_regions(size_t old_available) {
// Else, we do not promote this region (either in place or by copy) because it has received new allocations.

// During evacuation, we exclude from promotion regions for which age > tenure threshold, garbage < garbage-threshold,
// and get_top_before_promote() != tams
// used > pip_used_threshold, and get_top_before_promote() != tams
} else {
// Record this promotion-eligible candidate region. After sorting and selecting the best candidates below,
// we may still decide to exclude this promotion-eligible region from the current collection set. If this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,13 @@ void ShenandoahGenerationalEvacuationTask::maybe_promote_region(ShenandoahHeapRe
// more garbage than ShenandoahOldGarbageThreshold, we'll promote by evacuation. If there is room for evacuation
// in this cycle, the region will be in the collection set. If there is not room, the region will be promoted
// by evacuation in some future GC cycle.
promote_humongous(r);

// We do not promote primitive arrays because there's no performance penalty keeping them in young. When/if they
// become garbage, reclaiming the memory from young is much quicker and more efficient than reclaiming them from old.
oop obj = cast_to_oop(r->bottom());
if (!obj->is_typeArray()) {
promote_humongous(r);
}
} else if (r->is_regular() && (r->get_top_before_promote() != nullptr)) {
// Likewise, we cannot put promote-in-place regions into the collection set because that would also trigger
// the LRB to copy on reference fetch.
Expand Down
28 changes: 16 additions & 12 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1436,23 +1436,27 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const {
}
}

size_t ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) const {
size_t ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) {
assert(start->is_humongous_start(), "reclaim regions starting with the first one");

oop humongous_obj = cast_to_oop(start->bottom());
size_t size = humongous_obj->size();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this intentional? This looks like it would reintroduce #26256 (crash trying to access size of humongous object after its class has been unloaded).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch. I'll change how this is implemented.

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've fixed this.

size_t required_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize);
size_t index = start->index() + required_regions - 1;

assert(!start->has_live(), "liveness must be zero");

// Do not try to get the size of this humongous object. STW collections will
// have already unloaded classes, so an unmarked object may have a bad klass pointer.
ShenandoahHeapRegion* region = start;
size_t index = region->index();
do {
assert(region->is_humongous(), "Expect correct humongous start or continuation");
for(size_t i = 0; i < required_regions; i++) {
// Reclaim from tail. Otherwise, assertion fails when printing region to trace log,
// as it expects that every region belongs to a humongous region starting with a humongous start region.
ShenandoahHeapRegion* region = get_region(index --);

assert(region->is_humongous(), "expect correct humongous start or continuation");
assert(!region->is_cset(), "Humongous region should not be in collection set");
region->make_trash_immediate();
region = get_region(++index);
} while (region != nullptr && region->is_humongous_continuation());

// Return number of regions trashed
return index - start->index();
region->make_trash_immediate();
}
return required_regions;
}

class ShenandoahCheckCleanGCLABClosure : public ThreadClosure {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ class ShenandoahHeap : public CollectedHeap {
static inline void atomic_clear_oop(narrowOop* addr, oop compare);
static inline void atomic_clear_oop(narrowOop* addr, narrowOop compare);

size_t trash_humongous_region_at(ShenandoahHeapRegion *r) const;
size_t trash_humongous_region_at(ShenandoahHeapRegion *r);
Copy link
Contributor

Choose a reason for hiding this comment

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

Original method was const, removal seems unintentional.


static inline void increase_object_age(oop obj, uint additional_age);

Expand Down
16 changes: 15 additions & 1 deletion src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@
range, \
constraint) \
\
product(uintx, ShenandoahGenerationalMinPIPUsage, 30, EXPERIMENTAL, \
Copy link
Member

Choose a reason for hiding this comment

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

Looking at this quite late, but thought I'd leave these comments here nonetheless.

While I agree that copying takes up cycle time and cpu, there is a potential space cost to promoting in place regions with substantial garbage. Why was 30% used (i.e. 70% garbage) considered reasonable? I'd have expected something like 50 or a tad higher used (i.e. less than 50% garbage) to be eligible for PIP.

Did higher values not work well for specific benchmarks that were used to pick this threshold?

"(Generational mode only) What percent of a heap region " \
"should be used before we consider promoting a region in " \
"place? Regions with less than this amount of used will " \
"promoted by evacuation. A benefit of promoting in place " \
"is that less work is required by the GC at the time the " \
"region is promoted. A disadvantage of promoting in place " \
"is that this introduces fragmentation of old-gen memory, " \
"with old-gen regions scattered throughout the heap. Regions " \
"that have been promoted in place may need to be evacuated at " \
"a later time in order to compact old-gen memory to enable " \
"future humongous allocations.") \
range(0,100) \
\
product(uintx, ShenandoahGenerationalHumongousReserve, 0, EXPERIMENTAL, \
"(Generational mode only) What percent of the heap should be " \
"reserved for humongous objects if possible. Old-generation " \
Expand Down Expand Up @@ -165,7 +179,7 @@
"collector accepts. In percents of heap region size.") \
range(0,100) \
\
product(uintx, ShenandoahOldGarbageThreshold, 15, EXPERIMENTAL, \
product(uintx, ShenandoahOldGarbageThreshold, 25, EXPERIMENTAL, \
"How much garbage an old region has to contain before it would " \
"be taken for collection.") \
range(0,100) \
Expand Down