Skip to content

Commit 5bc71d4

Browse files
committed
8252500: ZGC on aarch64: Unable to allocate heap for certain Linux kernel configurations
1 parent 5f76deb commit 5bc71d4

File tree

1 file changed

+62
-2
lines changed

1 file changed

+62
-2
lines changed

src/hotspot/cpu/aarch64/gc/z/zGlobals_aarch64.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
*/
2323

2424
#include "precompiled.hpp"
25+
#include "gc/shared/gcLogPrecious.hpp"
2526
#include "gc/z/zGlobals.hpp"
2627
#include "runtime/globals.hpp"
2728
#include "utilities/globalDefinitions.hpp"
2829
#include "utilities/powerOfTwo.hpp"
2930

31+
#include <sys/mman.h>
32+
3033
//
3134
// The heap can have three different layouts, depending on the max heap size.
3235
//
@@ -135,9 +138,66 @@
135138
// * 63-48 Fixed (16-bits, always zero)
136139
//
137140

141+
// Default value if probing is not implemented for a certain platform: 128TB
142+
#define DEFAULT_MAX_ADDRESS_BIT 47
143+
// Minimum value returned, if probing fails: 64GB
144+
#define MINIMUM_MAX_ADDRESS_BIT 36
145+
146+
static size_t probe_valid_max_address_bit() {
147+
#ifdef LINUX
148+
size_t max_address_bit = 0;
149+
const size_t page_size = os::vm_page_size();
150+
for (int i = DEFAULT_MAX_ADDRESS_BIT; i > MINIMUM_MAX_ADDRESS_BIT && max_address_bit == 0; --i) {
151+
const uintptr_t base_addr = ((uintptr_t) 1U) << i;
152+
if (msync((void*)base_addr, page_size, MS_ASYNC) == 0) {
153+
// msync suceeded, the address is valid, and maybe even already mapped.
154+
max_address_bit = i;
155+
break;
156+
}
157+
if (errno != ENOMEM) {
158+
// Some error occured. This should never happen, but msync
159+
// has some undefined behavior, hence ignore this bit.
160+
#ifdef ASSERT
161+
fatal("Received %s while probing the address space for the highest valid bit", os::errno_name(errno));
162+
#else // ASSERT
163+
log_warning(gc)("Received %s while probing the address space for the highest valid bit", os::errno_name(errno));
164+
#endif // ASSERT
165+
continue;
166+
}
167+
// Since msync failed with ENOMEM, the page might not be mapped.
168+
// Try to map it, to see if the address is valid.
169+
void* result_addr = mmap((void*) base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
170+
if ((uintptr_t) result_addr == base_addr) {
171+
// address is valid
172+
max_address_bit = i;
173+
}
174+
if (result_addr != MAP_FAILED) {
175+
munmap(result_addr, page_size);
176+
}
177+
}
178+
if (max_address_bit == 0) {
179+
// probing failed, allocate a very high page and take that bit as the maximum
180+
uintptr_t high_addr = ((uintptr_t) 1U) << DEFAULT_MAX_ADDRESS_BIT;
181+
void* result_addr = mmap((void*) high_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
182+
if (result_addr != MAP_FAILED) {
183+
max_address_bit = BitsPerSize_t - count_leading_zeros((size_t) result_addr) - 1;
184+
munmap(result_addr, page_size);
185+
}
186+
}
187+
log_info_p(gc, init)("Probing address space for the highest valid bit: %zu", max_address_bit);
188+
if (max_address_bit < MINIMUM_MAX_ADDRESS_BIT) {
189+
return MINIMUM_MAX_ADDRESS_BIT;
190+
}
191+
return max_address_bit;
192+
#else // LINUX
193+
return DEFAULT_MAX_ADDRESS_BIT;
194+
#endif // LINUX
195+
}
196+
138197
size_t ZPlatformAddressOffsetBits() {
139-
const size_t min_address_offset_bits = 42; // 4TB
140-
const size_t max_address_offset_bits = 44; // 16TB
198+
const static size_t valid_max_address_bit = probe_valid_max_address_bit();
199+
const size_t max_address_offset_bits = valid_max_address_bit - 3;
200+
const size_t min_address_offset_bits = max_address_offset_bits - 2;
141201
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
142202
const size_t address_offset_bits = log2_intptr(address_offset);
143203
return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits);

0 commit comments

Comments
 (0)