mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-12 22:50:08 +00:00
8265268: Unify ReservedSpace reservation code in initialize and try_reserve_heap
Reviewed-by: tschatzl, iwalulya
This commit is contained in:
parent
191f1fc46c
commit
5db64c3353
@ -115,30 +115,82 @@ static void unmap_or_release_memory(char* base, size_t size, bool is_file_mapped
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method.
|
||||
static bool failed_to_reserve_as_requested(char* base, char* requested_address,
|
||||
const size_t size, bool special, bool is_file_mapped = false)
|
||||
{
|
||||
if (base == requested_address || requested_address == NULL)
|
||||
// Helper method
|
||||
static bool failed_to_reserve_as_requested(char* base, char* requested_address) {
|
||||
if (base == requested_address || requested_address == NULL) {
|
||||
return false; // did not fail
|
||||
}
|
||||
|
||||
if (base != NULL) {
|
||||
// Different reserve address may be acceptable in other cases
|
||||
// but for compressed oops heap should be at requested address.
|
||||
assert(UseCompressedOops, "currently requested address used only for compressed oops");
|
||||
log_debug(gc, heap, coops)("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, p2i(base), p2i(requested_address));
|
||||
// OS ignored requested address. Try different address.
|
||||
if (special) {
|
||||
if (!os::release_memory_special(base, size)) {
|
||||
fatal("os::release_memory_special failed");
|
||||
}
|
||||
} else {
|
||||
unmap_or_release_memory(base, size, is_file_mapped);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool use_explicit_large_pages(bool large) {
|
||||
return !os::can_commit_large_page_memory() && large;
|
||||
}
|
||||
|
||||
static bool large_pages_requested() {
|
||||
return UseLargePages &&
|
||||
(!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes));
|
||||
}
|
||||
|
||||
static char* reserve_memory(char* requested_address, const size_t size,
|
||||
const size_t alignment, int fd, bool exec) {
|
||||
char* base;
|
||||
// If the memory was requested at a particular address, use
|
||||
// os::attempt_reserve_memory_at() to avoid mapping over something
|
||||
// important. If the reservation fails, return NULL.
|
||||
if (requested_address != 0) {
|
||||
assert(is_aligned(requested_address, alignment),
|
||||
"Requested address " PTR_FORMAT " must be aligned to " SIZE_FORMAT,
|
||||
p2i(requested_address), alignment);
|
||||
base = attempt_map_or_reserve_memory_at(requested_address, size, fd, exec);
|
||||
} else {
|
||||
// Optimistically assume that the OS returns an aligned base pointer.
|
||||
// When reserving a large address range, most OSes seem to align to at
|
||||
// least 64K.
|
||||
base = map_or_reserve_memory(size, fd, exec);
|
||||
// Check alignment constraints. This is only needed when there is
|
||||
// no requested address.
|
||||
if (!is_aligned(base, alignment)) {
|
||||
// Base not aligned, retry.
|
||||
unmap_or_release_memory(base, size, fd != -1 /*is_file_mapped*/);
|
||||
// Map using the requested alignment.
|
||||
base = map_or_reserve_memory_aligned(size, alignment, fd, exec);
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static char* reserve_memory_special(char* requested_address, const size_t size,
|
||||
const size_t alignment, bool exec) {
|
||||
|
||||
log_trace(pagesize)("Attempt special mapping: size: " SIZE_FORMAT "%s, "
|
||||
"alignment: " SIZE_FORMAT "%s",
|
||||
byte_size_in_exact_unit(size), exact_unit_for_byte_size(size),
|
||||
byte_size_in_exact_unit(alignment), exact_unit_for_byte_size(alignment));
|
||||
|
||||
char* base = os::reserve_memory_special(size, alignment, requested_address, exec);
|
||||
if (base != NULL) {
|
||||
// Check alignment constraints.
|
||||
assert(is_aligned(base, alignment),
|
||||
"reserve_memory_special() returned an unaligned address, base: " PTR_FORMAT
|
||||
" alignment: " SIZE_FORMAT_HEX,
|
||||
p2i(base), alignment);
|
||||
} else {
|
||||
if (large_pages_requested()) {
|
||||
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
void ReservedSpace::clear_members() {
|
||||
initialize_members(NULL, 0, 0, false, false);
|
||||
}
|
||||
@ -153,6 +205,50 @@ void ReservedSpace::initialize_members(char* base, size_t size, size_t alignment
|
||||
_noaccess_prefix = 0;
|
||||
}
|
||||
|
||||
void ReservedSpace::reserve(size_t size, size_t alignment, bool large,
|
||||
char* requested_address,
|
||||
bool executable) {
|
||||
assert(is_aligned(size, alignment), "Size must be aligned to the requested alignment");
|
||||
|
||||
// There are basically three different cases that we need to handle below:
|
||||
// - Mapping backed by a file
|
||||
// - Mapping backed by explicit large pages
|
||||
// - Mapping backed by normal pages or transparent huge pages
|
||||
// The first two have restrictions that requires the whole mapping to be
|
||||
// committed up front. To record this the ReservedSpace is marked 'special'.
|
||||
|
||||
if (_fd_for_heap != -1) {
|
||||
// When there is a backing file directory for this space then whether
|
||||
// large pages are allocated is up to the filesystem of the backing file.
|
||||
// So UseLargePages is not taken into account for this reservation.
|
||||
char* base = reserve_memory(requested_address, size, alignment, _fd_for_heap, executable);
|
||||
if (base != NULL) {
|
||||
initialize_members(base, size, alignment, true, executable);
|
||||
}
|
||||
// Always return, not possible to fall back to reservation not using a file.
|
||||
return;
|
||||
} else if (use_explicit_large_pages(large)) {
|
||||
// System can't commit large pages i.e. use transparent huge pages and
|
||||
// the caller requested large pages. To satisfy this request we use
|
||||
// explicit large pages and these have to be committed up front to ensure
|
||||
// no reservations are lost.
|
||||
|
||||
char* base = reserve_memory_special(requested_address, size, alignment, executable);
|
||||
if (base != NULL) {
|
||||
// Successful reservation using large pages.
|
||||
initialize_members(base, size, alignment, true, executable);
|
||||
return;
|
||||
}
|
||||
// Failed to reserve explicit large pages, fall back to normal reservation.
|
||||
}
|
||||
|
||||
// Not a 'special' reservation.
|
||||
char* base = reserve_memory(requested_address, size, alignment, -1, executable);
|
||||
if (base != NULL) {
|
||||
// Successful mapping.
|
||||
initialize_members(base, size, alignment, false, executable);
|
||||
}
|
||||
}
|
||||
|
||||
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
|
||||
char* requested_address,
|
||||
@ -171,96 +267,18 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust alignment to not be 0.
|
||||
alignment = MAX2(alignment, (size_t)os::vm_page_size());
|
||||
|
||||
// If OS doesn't support demand paging for large page memory, we need
|
||||
// to use reserve_memory_special() to reserve and pin the entire region.
|
||||
// If there is a backing file directory for this space then whether
|
||||
// large pages are allocated is up to the filesystem of the backing file.
|
||||
// So we ignore the UseLargePages flag in this case.
|
||||
bool special = large && !os::can_commit_large_page_memory();
|
||||
if (special && _fd_for_heap != -1) {
|
||||
special = false;
|
||||
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
|
||||
log_debug(gc, heap)("Ignoring UseLargePages since large page support is up to the file system of the backing file for Java heap");
|
||||
}
|
||||
// Reserve the memory.
|
||||
reserve(size, alignment, large, requested_address, executable);
|
||||
|
||||
// Check that the requested address is used if given.
|
||||
if (failed_to_reserve_as_requested(_base, requested_address)) {
|
||||
// OS ignored the requested address, release the reservation.
|
||||
release();
|
||||
return;
|
||||
}
|
||||
|
||||
char* base = NULL;
|
||||
|
||||
if (special) {
|
||||
|
||||
base = os::reserve_memory_special(size, alignment, requested_address, executable);
|
||||
|
||||
if (base != NULL) {
|
||||
if (failed_to_reserve_as_requested(base, requested_address, size, true)) {
|
||||
// OS ignored requested address. Try different address.
|
||||
return;
|
||||
}
|
||||
// Check alignment constraints.
|
||||
assert((uintptr_t) base % alignment == 0,
|
||||
"Large pages returned a non-aligned address, base: "
|
||||
PTR_FORMAT " alignment: " SIZE_FORMAT_HEX,
|
||||
p2i(base), alignment);
|
||||
} else {
|
||||
// failed; try to reserve regular memory below. Reservation
|
||||
// should not be marked as special.
|
||||
special = false;
|
||||
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
|
||||
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (base == NULL) {
|
||||
// Optimistically assume that the OS returns an aligned base pointer.
|
||||
// When reserving a large address range, most OSes seem to align to at
|
||||
// least 64K.
|
||||
|
||||
// If the memory was requested at a particular address, use
|
||||
// os::attempt_reserve_memory_at() to avoid over mapping something
|
||||
// important. If available space is not detected, return NULL.
|
||||
|
||||
if (requested_address != 0) {
|
||||
base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap, executable);
|
||||
if (failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) {
|
||||
// OS ignored requested address. Try different address.
|
||||
base = NULL;
|
||||
}
|
||||
} else {
|
||||
base = map_or_reserve_memory(size, _fd_for_heap, executable);
|
||||
}
|
||||
|
||||
if (base == NULL) return;
|
||||
|
||||
// Check alignment constraints
|
||||
if ((((size_t)base) & (alignment - 1)) != 0) {
|
||||
// Base not aligned, retry
|
||||
unmap_or_release_memory(base, size, _fd_for_heap != -1 /*is_file_mapped*/);
|
||||
|
||||
// Make sure that size is aligned
|
||||
size = align_up(size, alignment);
|
||||
base = map_or_reserve_memory_aligned(size, alignment, _fd_for_heap, executable);
|
||||
|
||||
if (requested_address != 0 &&
|
||||
failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) {
|
||||
// As a result of the alignment constraints, the allocated base differs
|
||||
// from the requested address. Return back to the caller who can
|
||||
// take remedial action (like try again without a requested address).
|
||||
assert(_base == NULL, "should be");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If heap is reserved with a backing file, the entire space has been committed. So set the special flag to true
|
||||
if (_fd_for_heap != -1) {
|
||||
special = true;
|
||||
}
|
||||
|
||||
// Done
|
||||
initialize_members(base, size, alignment, special, executable);
|
||||
}
|
||||
|
||||
ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment) {
|
||||
@ -375,69 +393,16 @@ void ReservedHeapSpace::try_reserve_heap(size_t size,
|
||||
release();
|
||||
}
|
||||
|
||||
// If OS doesn't support demand paging for large page memory, we need
|
||||
// to use reserve_memory_special() to reserve and pin the entire region.
|
||||
// If there is a backing file directory for this space then whether
|
||||
// large pages are allocated is up to the filesystem of the backing file.
|
||||
// So we ignore the UseLargePages flag in this case.
|
||||
bool special = large && !os::can_commit_large_page_memory();
|
||||
if (special && _fd_for_heap != -1) {
|
||||
special = false;
|
||||
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
|
||||
log_debug(gc, heap)("Cannot allocate large pages for Java Heap when AllocateHeapAt option is set.");
|
||||
}
|
||||
}
|
||||
char* base = NULL;
|
||||
|
||||
// Try to reserve the memory for the heap.
|
||||
log_trace(gc, heap, coops)("Trying to allocate at address " PTR_FORMAT
|
||||
" heap of size " SIZE_FORMAT_HEX,
|
||||
p2i(requested_address),
|
||||
size);
|
||||
|
||||
if (special) {
|
||||
base = os::reserve_memory_special(size, alignment, requested_address, false);
|
||||
reserve(size, alignment, large, requested_address, false);
|
||||
|
||||
if (base != NULL) {
|
||||
// Check alignment constraints.
|
||||
assert((uintptr_t) base % alignment == 0,
|
||||
"Large pages returned a non-aligned address, base: "
|
||||
PTR_FORMAT " alignment: " SIZE_FORMAT_HEX,
|
||||
p2i(base), alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (base == NULL) {
|
||||
// Failed; try to reserve regular memory below. Reservation
|
||||
// should not be marked as special.
|
||||
special = false;
|
||||
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
|
||||
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
|
||||
}
|
||||
|
||||
if (requested_address != 0) {
|
||||
base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap, executable());
|
||||
} else {
|
||||
// Optimistically assume that the OSes returns an aligned base pointer.
|
||||
// When reserving a large address range, most OSes seem to align to at
|
||||
// least 64K.
|
||||
// If the returned memory is not aligned we will release and retry.
|
||||
base = map_or_reserve_memory(size, _fd_for_heap, executable());
|
||||
}
|
||||
}
|
||||
if (base == NULL) { return; }
|
||||
|
||||
// If heap is reserved with a backing file, the entire space has been committed. So set the special flag to true
|
||||
if (_fd_for_heap != -1) {
|
||||
special = true;
|
||||
}
|
||||
|
||||
// Done
|
||||
initialize_members(base, size, alignment, special, false);
|
||||
|
||||
// Check alignment constraints
|
||||
if (!is_aligned(base, alignment)) {
|
||||
// Check alignment constraints.
|
||||
if (is_reserved() && !is_aligned(_base, _alignment)) {
|
||||
// Base not aligned, retry.
|
||||
release();
|
||||
}
|
||||
@ -641,6 +606,12 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large,
|
||||
vm_exit_during_initialization(
|
||||
err_msg("Could not create file for Heap at location %s", heap_allocation_directory));
|
||||
}
|
||||
// When there is a backing file directory for this space then whether
|
||||
// large pages are allocated is up to the filesystem of the backing file.
|
||||
// If requested, let the user know that explicit large pages can't be used.
|
||||
if (use_explicit_large_pages(large) && large_pages_requested()) {
|
||||
log_debug(gc, heap)("Cannot allocate explicit large pages for Java Heap when AllocateHeapAt option is set.");
|
||||
}
|
||||
}
|
||||
|
||||
// Heap size should be aligned to alignment, too.
|
||||
|
||||
@ -63,6 +63,9 @@ class ReservedSpace {
|
||||
char* requested_address,
|
||||
bool executable);
|
||||
|
||||
void reserve(size_t size, size_t alignment, bool large,
|
||||
char* requested_address,
|
||||
bool executable);
|
||||
public:
|
||||
// Constructor
|
||||
ReservedSpace();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user