src/share/vm/memory/metaspace.cpp
Print this page
rev 6722 : 8049599: MetaspaceGC::_capacity_until_GC can overflow
Reviewed-by: jmasa, stefank
*** 1412,1425 ****
size_t value = (size_t)OrderAccess::load_ptr_acquire(&_capacity_until_GC);
assert(value >= MetaspaceSize, "Not initialied properly?");
return value;
}
! size_t MetaspaceGC::inc_capacity_until_GC(size_t v) {
assert_is_size_aligned(v, Metaspace::commit_alignment());
! return (size_t)Atomic::add_ptr(v, &_capacity_until_GC);
}
size_t MetaspaceGC::dec_capacity_until_GC(size_t v) {
assert_is_size_aligned(v, Metaspace::commit_alignment());
--- 1412,1446 ----
size_t value = (size_t)OrderAccess::load_ptr_acquire(&_capacity_until_GC);
assert(value >= MetaspaceSize, "Not initialied properly?");
return value;
}
! bool MetaspaceGC::inc_capacity_until_GC(size_t v, size_t* new_cap_until_GC, size_t* old_cap_until_GC) {
assert_is_size_aligned(v, Metaspace::commit_alignment());
! size_t capacity_until_GC = (size_t) _capacity_until_GC;
! size_t new_value = capacity_until_GC + v;
!
! if (new_value < capacity_until_GC) {
! // The addition wrapped around, set new_value to aligned max value.
! new_value = align_size_down(max_uintx, Metaspace::commit_alignment());
! }
!
! intptr_t expected = (intptr_t) capacity_until_GC;
! intptr_t actual = Atomic::cmpxchg_ptr((intptr_t) new_value, &_capacity_until_GC, expected);
!
! if (expected != actual) {
! return false;
! }
!
! if (new_cap_until_GC != NULL) {
! *new_cap_until_GC = new_value;
! }
! if (old_cap_until_GC != NULL) {
! *old_cap_until_GC = capacity_until_GC;
! }
! return true;
}
size_t MetaspaceGC::dec_capacity_until_GC(size_t v) {
assert_is_size_aligned(v, Metaspace::commit_alignment());
*** 1515,1525 ****
// increment the HWM.
size_t expand_bytes = minimum_desired_capacity - capacity_until_GC;
expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment());
// Don't expand unless it's significant
if (expand_bytes >= MinMetaspaceExpansion) {
! size_t new_capacity_until_GC = MetaspaceGC::inc_capacity_until_GC(expand_bytes);
Metaspace::tracer()->report_gc_threshold(capacity_until_GC,
new_capacity_until_GC,
MetaspaceGCThresholdUpdater::ComputeNewSize);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr(" expanding:"
--- 1536,1549 ----
// increment the HWM.
size_t expand_bytes = minimum_desired_capacity - capacity_until_GC;
expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment());
// Don't expand unless it's significant
if (expand_bytes >= MinMetaspaceExpansion) {
! size_t new_capacity_until_GC = 0;
! bool succeeded = MetaspaceGC::inc_capacity_until_GC(expand_bytes, &new_capacity_until_GC);
! assert(succeeded, "Should always succesfully increment HWM when at safepoint");
!
Metaspace::tracer()->report_gc_threshold(capacity_until_GC,
new_capacity_until_GC,
MetaspaceGCThresholdUpdater::ComputeNewSize);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr(" expanding:"
*** 3317,3339 ****
MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) {
size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord);
assert(delta_bytes > 0, "Must be");
! size_t after_inc = MetaspaceGC::inc_capacity_until_GC(delta_bytes);
!
! // capacity_until_GC might be updated concurrently, must calculate previous value.
! size_t before_inc = after_inc - delta_bytes;
! tracer()->report_gc_threshold(before_inc, after_inc,
MetaspaceGCThresholdUpdater::ExpandAndAllocate);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT
! " to " SIZE_FORMAT, before_inc, after_inc);
}
! return allocate(word_size, mdtype);
}
// Space allocated in the Metaspace. This may
// be across several metadata virtual spaces.
char* Metaspace::bottom() const {
--- 3341,3373 ----
MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) {
size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord);
assert(delta_bytes > 0, "Must be");
! size_t before = 0;
! size_t after = 0;
! MetaWord* res;
! bool incremented;
!
! // Each thread increments the HWM at most once. Even if the thread fails to increment
! // the HWM, an allocation is still attempted. This is because another thread must then
! // have incremented the HWM and therefore the allocation might still succeed.
! do {
! incremented = MetaspaceGC::inc_capacity_until_GC(delta_bytes, &after, &before);
! res = allocate(word_size, mdtype);
! } while (!incremented && res == NULL);
! if (incremented) {
! tracer()->report_gc_threshold(before, after,
MetaspaceGCThresholdUpdater::ExpandAndAllocate);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT
! " to " SIZE_FORMAT, before, after);
! }
}
! return res;
}
// Space allocated in the Metaspace. This may
// be across several metadata virtual spaces.
char* Metaspace::bottom() const {