diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp index 1b11c696d18..7927ec4a07c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalFullGC.cpp @@ -144,7 +144,7 @@ void ShenandoahGenerationalFullGC::account_for_region(ShenandoahHeapRegion* r, s void ShenandoahGenerationalFullGC::maybe_coalesce_and_fill_region(ShenandoahHeapRegion* r) { if (r->is_pinned() && r->is_old() && r->is_active() && !r->is_humongous()) { r->begin_preemptible_coalesce_and_fill(); - r->oop_coalesce_and_fill(false); + r->oop_coalesce_and_fill(/* cancellable = */ false, /* do_card_table_updates = */ false); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index c5b9c929eed..063c55ac9c3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -452,7 +452,7 @@ void ShenandoahHeapRegion::print_on(outputStream* st) const { } // oop_iterate without closure, return true if completed without cancellation -bool ShenandoahHeapRegion::oop_coalesce_and_fill(bool cancellable) { +bool ShenandoahHeapRegion::oop_coalesce_and_fill(bool cancellable, bool do_card_table_updates) { assert(!is_humongous(), "No need to fill or coalesce humongous regions"); if (!is_active()) { @@ -489,7 +489,16 @@ bool ShenandoahHeapRegion::oop_coalesce_and_fill(bool cancellable) { size_t fill_size = next_marked_obj - obj_addr; assert(fill_size >= ShenandoahHeap::min_fill_size(), "previously allocated object known to be larger than min_size"); ShenandoahHeap::fill_with_object(obj_addr, fill_size); - heap->old_generation()->card_scan()->coalesce_objects(obj_addr, fill_size); + if (do_card_table_updates) { + heap->old_generation()->card_scan()->coalesce_objects(obj_addr, fill_size); + } else { + // A humongous object allocation failure during evacuation will skip the degenerated cycle and + // jump straight to a full GC. If this region is pinned when the full GC cycle starts, it will + // not be compacted. Therefore, if the region is old, we must fill in any unmarked objects. However, + // promoted objects will not have been registered yet, so we cannot use the card table here. + assert(heap->is_full_gc_in_progress(), "Can only skip card table updates during a full GC"); + } + obj_addr = next_marked_obj; } if (cancellable && heap->cancelled_gc()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 9040a81848e..71a7ee1de01 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -447,7 +447,7 @@ public: // This is used by old-gen GC following concurrent marking to make old-gen HeapRegions parsable. Old regions must be // parsable because the mark bitmap is not reliable during the concurrent old mark. // Return true iff region is completely coalesced and filled. Returns false if cancelled before task is complete. - bool oop_coalesce_and_fill(bool cancellable); + bool oop_coalesce_and_fill(bool cancellable, bool do_card_table_updates = true); // Invoke closure on every reference contained within the humongous object that spans this humongous // region if the reference is contained within a DIRTY card and the reference is no more than words following diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp index f139f94fc8b..59ed97dd513 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp @@ -28,8 +28,6 @@ #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPLAB.hpp" #include "logging/log.hpp" -#include "runtime/globals.hpp" -#include "runtime/javaThread.hpp" #include "utilities/copy.hpp" ShenandoahPLAB::ShenandoahPLAB() : @@ -46,9 +44,7 @@ ShenandoahPLAB::ShenandoahPLAB() : } ShenandoahPLAB::~ShenandoahPLAB() { - if (_plab != nullptr) { - delete _plab; - } + delete _plab; } void ShenandoahPLAB::subtract_from_promoted(size_t increment) { @@ -119,7 +115,7 @@ HeapWord* ShenandoahPLAB::allocate_slow(size_t size, bool is_promotion) { } if (_plab->words_remaining() < plab_min_size) { - // Retire current PLAB. This takes care of any PLAB book-keeping. + // Retire current PLAB. This takes care of any PLAB bookkeeping. retire(); size_t actual_size = 0; @@ -191,10 +187,12 @@ void ShenandoahPLAB::retire() { log_debug(gc, plab)("Retire PLAB, unexpend unpromoted: %zu", not_promoted * HeapWordSize); _heap->old_generation()->unexpend_promoted(not_promoted); } - const size_t original_waste = _plab->waste(); - HeapWord* const top = _plab->top(); // plab->retire() overwrites unused memory between plab->top() and plab->hard_end() with a dummy object to make memory parsable. - // It adds the size of this unused memory, in words, to plab->waste(). + // We do _not_ need to register this remnant object with the card table because all paths where a PLAB object would + // be created are covered by a subsequent phase in the cycle. For the concurrent and degenerated cycles, all PLABs + // are retired in preparation for update-references. All objects in these PLABs will be registered by update-card-tables. + // For a full GC, the entire remembered set will be rebuilt in the final phase. Note also that an empty TLAB will _not_ + // create a filler object when it is retired. _plab->retire(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 5df88c0fc0a..19c33c77b26 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -388,7 +388,7 @@ public: _used(0), _committed(0), _garbage(0), _regions(0), _humongous_waste(0), _trashed_regions(0), _trashed_used(0) { _region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); - // Retired regions are not necessarily filled, thouugh their remnant memory is considered used. + // Retired regions are not necessarily filled, though their remnant memory is considered used. _min_free_size = PLAB::min_size() * HeapWordSize; };