Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions src/hotspot/share/gc/shared/gcVMOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ void VM_GC_Operation::doit_epilogue() {
}

bool VM_GC_HeapInspection::doit_prologue() {
if (_full_gc && UseZGC) {
// ZGC cannot perform a synchronous GC cycle from within the VM thread.
if (_full_gc && (UseZGC || UseShenandoahGC)) {
// ZGC and Shenandoah cannot perform a synchronous GC cycle from within the VM thread.
// So VM_GC_HeapInspection::collect() is a noop. To respect the _full_gc
// flag a synchronous GC cycle is performed from the caller thread in the
// prologue.
Expand Down
12 changes: 12 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,18 @@ size_t ShenandoahHeap::max_tlab_size() const {
return ShenandoahHeapRegion::max_tlab_size_words();
}

void ShenandoahHeap::collect_as_vm_thread(GCCause::Cause cause) {
// These requests are ignored because we can't easily have Shenandoah jump into
// a synchronous (degenerated or full) cycle while it is in the middle of a concurrent
// cycle. We _could_ cancel the concurrent cycle and then try to run a cycle directly
// on the VM thread, but this would confuse the control thread mightily and doesn't
// seem worth the trouble. Instead, we will have the caller thread run (and wait for) a
// concurrent cycle in the prologue of the heap inspect/dump operation. This is how
// other concurrent collectors in the JVM handle this scenario as well.
assert(Thread::current()->is_VM_thread(), "Should be the VM thread");
guarantee(cause == GCCause::_heap_dump || cause == GCCause::_heap_inspection, "Invalid cause");
}

void ShenandoahHeap::collect(GCCause::Cause cause) {
control_thread()->request_gc(cause);
}
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo {
MemRegion reserved_region() const { return _reserved; }
bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); }

void collect_as_vm_thread(GCCause::Cause cause) override;
void collect(GCCause::Cause cause) override;
void do_full_collection(bool clear_all_soft_refs) override;

Expand Down
9 changes: 4 additions & 5 deletions src/hotspot/share/services/heapDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2364,11 +2364,10 @@ void VM_HeapDumper::dump_threads(AbstractDumpWriter* writer) {
}

bool VM_HeapDumper::doit_prologue() {
if (_gc_before_heap_dump && UseZGC) {
// ZGC cannot perform a synchronous GC cycle from within the VM thread.
// So ZCollectedHeap::collect_as_vm_thread() is a noop. To respect the
// _gc_before_heap_dump flag a synchronous GC cycle is performed from
// the caller thread in the prologue.
if (_gc_before_heap_dump && (UseZGC || UseShenandoahGC)) {
// ZGC and Shenandoah cannot perform a synchronous GC cycle from within the VM thread.
// So collect_as_vm_thread() is a noop. To respect the _gc_before_heap_dump flag a
// synchronous GC cycle is performed from the caller thread in the prologue.
Universe::heap()->collect(GCCause::_heap_dump);
}
return VM_GC_Operation::doit_prologue();
Expand Down