8334403: Unify behavior of os::committed_in_range across OSes

Reviewed-by: stuefe, jsjolen
This commit is contained in:
Robert Toyonaga 2026-06-03 16:05:09 +00:00 committed by Thomas Stuefe
parent 7a7f37f0e5
commit 79923019f5
5 changed files with 103 additions and 76 deletions

View File

@ -167,11 +167,11 @@ void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool che
}
}
bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {
bool os::first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size) {
#ifdef _AIX
committed_start = start;
committed_size = size;
resident_start = start;
resident_size = size;
return true;
#else
@ -188,10 +188,10 @@ bool os::committed_in_range(address start, size_t size, address& committed_start
assert(is_aligned(start, page_sz), "Start address must be page aligned");
assert(is_aligned(size, page_sz), "Size must be page aligned");
committed_start = nullptr;
resident_start = nullptr;
int loops = checked_cast<int>((pages + stripe - 1) / stripe);
int committed_pages = 0;
int resident_pages = 0;
address loop_base = start;
bool found_range = false;
@ -210,7 +210,7 @@ bool os::committed_in_range(address start, size_t size, address& committed_start
// During shutdown, some memory goes away without properly notifying NMT,
// E.g. ConcurrentGCThread/WatcherThread can exit without deleting thread object.
// Bailout and return as not committed for now.
// Bailout and return as not resident for now.
if (mincore_return_value == -1 && errno == ENOMEM) {
return false;
}
@ -224,32 +224,32 @@ bool os::committed_in_range(address start, size_t size, address& committed_start
assert(mincore_return_value == 0, "Range must be valid");
// Process this stripe
for (uintx vecIdx = 0; vecIdx < pages_to_query; vecIdx ++) {
if ((vec[vecIdx] & 0x01) == 0) { // not committed
if ((vec[vecIdx] & 0x01) == 0) { // not resident
// End of current contiguous region
if (committed_start != nullptr) {
if (resident_start != nullptr) {
found_range = true;
break;
}
} else { // committed
} else { // resident
// Start of region
if (committed_start == nullptr) {
committed_start = loop_base + page_sz * vecIdx;
if (resident_start == nullptr) {
resident_start = loop_base + page_sz * vecIdx;
}
committed_pages ++;
resident_pages ++;
}
}
loop_base += pages_to_query * page_sz;
}
if (committed_start != nullptr) {
assert(committed_pages > 0, "Must have committed region");
assert(committed_pages <= int(size / page_sz), "Can not commit more than it has");
assert(committed_start >= start && committed_start < start + size, "Out of range");
committed_size = page_sz * committed_pages;
if (resident_start != nullptr) {
assert(resident_pages > 0, "Must have a resident region");
assert(resident_pages <= int(size / page_sz), "Resident size exceeds region size");
assert(resident_start >= start && resident_start < start + size, "Out of range");
resident_size = page_sz * resident_pages;
return true;
} else {
assert(committed_pages == 0, "Should not have committed region");
assert(resident_pages == 0, "Should not have a resident region");
return false;
}
#endif

View File

@ -465,36 +465,63 @@ void os::current_stack_base_and_size(address* stack_base, size_t* stack_size) {
*stack_size = size;
}
bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {
MEMORY_BASIC_INFORMATION minfo;
committed_start = nullptr;
committed_size = 0;
address top = start + size;
const address start_addr = start;
while (start < top) {
VirtualQuery(start, &minfo, sizeof(minfo));
if ((minfo.State & MEM_COMMIT) == 0) { // not committed
if (committed_start != nullptr) {
break;
}
} else { // committed
if (committed_start == nullptr) {
committed_start = start;
}
size_t offset = start - (address)minfo.BaseAddress;
committed_size += minfo.RegionSize - offset;
}
start = (address)minfo.BaseAddress + minfo.RegionSize;
}
bool os::first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size) {
constexpr size_t stripe = 1024; // query this many pages each time
PSAPI_WORKING_SET_EX_INFORMATION wsinfo[stripe];
if (committed_start == nullptr) {
assert(committed_size == 0, "Sanity");
return false;
} else {
assert(committed_start >= start_addr && committed_start < top, "Out of range");
// current region may go beyond the limit, trim to the limit
committed_size = MIN2(committed_size, size_t(top - committed_start));
size_t page_sz = os::vm_page_size();
uintx pages_left = size / page_sz;
assert(is_aligned(start, page_sz), "Start address must be page aligned");
assert(is_aligned(size, page_sz), "Size must be page aligned");
resident_start = nullptr;
uintx loops = (pages_left + stripe - 1) / stripe;
uintx resident_pages = 0;
address pos = start;
bool found_range = false;
for (uintx index = 0; index < loops && !found_range; index++) {
assert(pages_left > 0, "Nothing to do");
uintx pages_to_query = MIN2(pages_left, stripe);
pages_left -= pages_to_query;
for (uintx i = 0; i < pages_to_query; i++) {
wsinfo[i].VirtualAddress = (PVOID)(pos + i * page_sz);
}
BOOL success = QueryWorkingSetEx(GetCurrentProcess(), wsinfo, pages_to_query * sizeof(PSAPI_WORKING_SET_EX_INFORMATION));
if (!success) {
return false;
}
for (uintx i = 0; i < pages_to_query; i++) {
if (wsinfo[i].VirtualAttributes.Valid == 0) {
if (resident_start != nullptr) {
found_range = true;
break;
}
// Still searching for start of resident region
} else {
if (resident_start == nullptr) {
// Found first resident page in region
resident_start = pos + i * page_sz;
}
resident_pages++;
}
}
pos += pages_to_query * page_sz;
}
if (resident_start != nullptr) {
assert(resident_pages > 0, "Must have a resident region");
assert(resident_pages <= size / page_sz, "Resident size exceeds region size");
assert(resident_start >= start && resident_start < start + size, "Out of range");
resident_size = page_sz * resident_pages;
return true;
} else {
assert(resident_pages == 0, "Should not have a resident region");
return false;
}
}

View File

@ -283,7 +283,7 @@ bool RegionIterator::next_committed(address& committed_start, size_t& committed_
const size_t page_sz = os::vm_page_size();
const size_t current_size = end() - _current_start;
if (os::committed_in_range(_current_start, current_size, committed_start, committed_size)) {
if (os::first_resident_in_range(_current_start, current_size, committed_start, committed_size)) {
assert(committed_start != nullptr, "Must be");
assert(committed_size > 0 && is_aligned(committed_size, os::vm_page_size()), "Must be");

View File

@ -440,9 +440,9 @@ class os: AllStatic {
public:
// get allowed minimum java stack size
static jlong get_minimum_java_stack_size();
// Find committed memory region within specified range (start, start + size),
// return true if found any
static bool committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size);
// Find the first resident memory region within the specified range (start, start + size) beginning at the start address.
// Returns true if successful or false if none are found.
static bool first_resident_in_range(address start, size_t size, address& resident_start, size_t& resident_size);
// OS interface to Virtual Memory

View File

@ -169,8 +169,8 @@ public:
static void test_partial_region() {
bool result;
size_t committed_size;
address committed_start;
size_t resident_size;
address resident_start;
size_t index;
const size_t page_sz = os::vm_page_size();
@ -187,36 +187,36 @@ public:
}
// Test whole range
result = os::committed_in_range((address)base, size, committed_start, committed_size);
result = os::first_resident_in_range((address)base, size, resident_start, resident_size);
ASSERT_TRUE(result);
ASSERT_EQ(num_pages * page_sz, committed_size);
ASSERT_EQ(committed_start, (address)base);
ASSERT_EQ(num_pages * page_sz, resident_size);
ASSERT_EQ(resident_start, (address)base);
// Test beginning of the range
result = os::committed_in_range((address)base, 2 * page_sz, committed_start, committed_size);
result = os::first_resident_in_range((address)base, 2 * page_sz, resident_start, resident_size);
ASSERT_TRUE(result);
ASSERT_EQ(2 * page_sz, committed_size);
ASSERT_EQ(committed_start, (address)base);
ASSERT_EQ(2 * page_sz, resident_size);
ASSERT_EQ(resident_start, (address)base);
// Test end of the range
result = os::committed_in_range((address)(base + page_sz), 3 * page_sz, committed_start, committed_size);
result = os::first_resident_in_range((address)(base + page_sz), 3 * page_sz, resident_start, resident_size);
ASSERT_TRUE(result);
ASSERT_EQ(3 * page_sz, committed_size);
ASSERT_EQ(committed_start, (address)(base + page_sz));
ASSERT_EQ(3 * page_sz, resident_size);
ASSERT_EQ(resident_start, (address)(base + page_sz));
// Test middle of the range
result = os::committed_in_range((address)(base + page_sz), 2 * page_sz, committed_start, committed_size);
result = os::first_resident_in_range((address)(base + page_sz), 2 * page_sz, resident_start, resident_size);
ASSERT_TRUE(result);
ASSERT_EQ(2 * page_sz, committed_size);
ASSERT_EQ(committed_start, (address)(base + page_sz));
ASSERT_EQ(2 * page_sz, resident_size);
ASSERT_EQ(resident_start, (address)(base + page_sz));
os::release_memory(base, size);
}
static void test_committed_in_range(size_t num_pages, size_t pages_to_touch) {
static void test_first_resident_in_range(size_t num_pages, size_t pages_to_touch) {
bool result;
size_t committed_size;
address committed_start;
size_t resident_size;
address resident_start;
size_t index;
const size_t page_sz = os::vm_page_size();
@ -228,7 +228,7 @@ public:
result = os::commit_memory(base, size, !ExecMem);
ASSERT_TRUE(result);
result = os::committed_in_range((address)base, size, committed_start, committed_size);
result = os::first_resident_in_range((address)base, size, resident_start, resident_size);
ASSERT_FALSE(result);
// Touch pages
@ -236,14 +236,14 @@ public:
base[index * page_sz] = 'a';
}
result = os::committed_in_range((address)base, size, committed_start, committed_size);
result = os::first_resident_in_range((address)base, size, resident_start, resident_size);
ASSERT_TRUE(result);
ASSERT_EQ(pages_to_touch * page_sz, committed_size);
ASSERT_EQ(committed_start, (address)base);
ASSERT_EQ(pages_to_touch * page_sz, resident_size);
ASSERT_EQ(resident_start, (address)base);
os::uncommit_memory(base, size, false);
result = os::committed_in_range((address)base, size, committed_start, committed_size);
result = os::first_resident_in_range((address)base, size, resident_start, resident_size);
ASSERT_FALSE(result);
os::release_memory(base, size);
@ -266,9 +266,9 @@ TEST_VM(NMTCommittedVirtualMemoryTracker, test_committed_virtualmemory_region) {
}
#if !defined(_WINDOWS) && !defined(_AIX)
TEST_VM(NMTCommittedVirtualMemory, test_committed_in_range){
CommittedVirtualMemoryTest::test_committed_in_range(1024, 1024);
CommittedVirtualMemoryTest::test_committed_in_range(2, 1);
#if !defined(_AIX)
TEST_VM(NMTCommittedVirtualMemory, test_first_resident_in_range){
CommittedVirtualMemoryTest::test_first_resident_in_range(1024, 1024);
CommittedVirtualMemoryTest::test_first_resident_in_range(2, 1);
}
#endif