From 11fdca06345542b8d5e54feb1d16f17c2bcb1a82 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 23 Feb 2024 10:48:50 +0000 Subject: [PATCH] 8325202: gc/g1/TestMarkStackOverflow.java intermittently crash: G1CMMarkStack::ChunkAllocator::allocate_new_chunk Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 25 +++++++++++++------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 8 ++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index cab9f52a009..5df9a097cfe 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -152,7 +152,8 @@ G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::ChunkAllocator::allocate_new_ MutexLocker x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); if (Atomic::load_acquire(&_buckets[bucket]) == nullptr) { - if (!expand()) { + size_t desired_capacity = bucket_size(bucket) * 2; + if (!try_expand_to(desired_capacity)) { return nullptr; } } @@ -196,23 +197,28 @@ bool G1CMMarkStack::ChunkAllocator::initialize(size_t initial_capacity, size_t m return true; } -bool G1CMMarkStack::ChunkAllocator::expand() { +bool G1CMMarkStack::ChunkAllocator::try_expand_to(size_t desired_capacity) { if (_capacity == _max_capacity) { log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _capacity); return false; } - size_t old_capacity = _capacity; - // Double capacity if possible. - size_t new_capacity = MIN2(old_capacity * 2, _max_capacity); - if (reserve(new_capacity)) { + size_t old_capacity = _capacity; + desired_capacity = MIN2(desired_capacity, _max_capacity); + + if (reserve(desired_capacity)) { log_debug(gc)("Expanded the mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks", - old_capacity, new_capacity); + old_capacity, desired_capacity); return true; } return false; } +bool G1CMMarkStack::ChunkAllocator::try_expand() { + size_t new_capacity = _capacity * 2; + return try_expand_to(new_capacity); +} + G1CMMarkStack::ChunkAllocator::~ChunkAllocator() { if (_buckets == nullptr) { return; @@ -234,6 +240,9 @@ bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { size_t highest_bucket = get_bucket(new_capacity - 1); size_t i = get_bucket(_capacity); + // Allocate all buckets associated with indexes between the current capacity (_capacity) + // and the new capacity (new_capacity). This step ensures that there are no gaps in the + // array and that the capacity accurately reflects the reserved memory. for (; i <= highest_bucket; i++) { if (Atomic::load_acquire(&_buckets[i]) != nullptr) { continue; // Skip over already allocated buckets. @@ -261,7 +270,7 @@ bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { } void G1CMMarkStack::expand() { - _chunk_allocator.expand(); + _chunk_allocator.try_expand(); } void G1CMMarkStack::add_chunk_to_list(TaskQueueEntryChunk* volatile* list, TaskQueueEntryChunk* elem) { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index ccd35bed64f..c58b99437b8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -145,7 +145,7 @@ private: // within the bucket. Additionally, each new bucket added to the growable array doubles the capacity of // the growable array. // - // Illustration of the Growable Array data structure. + // Illustration of the growable array data structure. // // +----+ +----+----+ // | |------->| | | @@ -174,7 +174,7 @@ private: size_t bucket_size(size_t bucket) { return (bucket == 0) ? _min_capacity : - _min_capacity * ( 1ULL << (bucket -1)); + _min_capacity * ( 1ULL << (bucket - 1)); } static unsigned int find_highest_bit(uintptr_t mask) { @@ -225,7 +225,9 @@ private: size_t capacity() const { return _capacity; } - bool expand(); + // Expand the mark stack doubling its size. + bool try_expand(); + bool try_expand_to(size_t desired_capacity); TaskQueueEntryChunk* allocate_new_chunk(); };