8255254: Split os::reserve_memory and os::map_memory_to_file interfaces

Reviewed-by: stefank, stuefe
This commit is contained in:
Anton Kozlov 2020-10-27 20:37:01 +00:00 committed by Vladimir Kempik
parent dc85a3fe81
commit acd0e2560c
9 changed files with 116 additions and 83 deletions

View file

@ -2236,7 +2236,7 @@ bool os::can_execute_large_page_memory() {
return false; return false;
} }
char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
assert(file_desc >= 0, "file_desc is not valid"); assert(file_desc >= 0, "file_desc is not valid");
char* result = NULL; char* result = NULL;

View file

@ -1905,7 +1905,7 @@ bool os::can_execute_large_page_memory() {
return false; return false;
} }
char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
assert(file_desc >= 0, "file_desc is not valid"); assert(file_desc >= 0, "file_desc is not valid");
char* result = pd_attempt_reserve_memory_at(requested_addr, bytes); char* result = pd_attempt_reserve_memory_at(requested_addr, bytes);
if (result != NULL) { if (result != NULL) {

View file

@ -4214,7 +4214,7 @@ bool os::can_execute_large_page_memory() {
return UseTransparentHugePages || UseHugeTLBFS; return UseTransparentHugePages || UseHugeTLBFS;
} }
char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
assert(file_desc >= 0, "file_desc is not valid"); assert(file_desc >= 0, "file_desc is not valid");
char* result = pd_attempt_reserve_memory_at(requested_addr, bytes); char* result = pd_attempt_reserve_memory_at(requested_addr, bytes);
if (result != NULL) { if (result != NULL) {

View file

@ -297,37 +297,18 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in
return map_memory_to_file(base, size, fd); return map_memory_to_file(base, size, fd);
} }
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED, static size_t calculate_aligned_extra_size(size_t size, size_t alignment) {
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
// rather than unmapping and remapping the whole chunk to get requested alignment.
char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
assert((alignment & (os::vm_allocation_granularity() - 1)) == 0, assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
"Alignment must be a multiple of allocation granularity (page size)"); "Alignment must be a multiple of allocation granularity (page size)");
assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned"); assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
size_t extra_size = size + alignment; size_t extra_size = size + alignment;
assert(extra_size >= size, "overflow, size is too large to allow alignment"); assert(extra_size >= size, "overflow, size is too large to allow alignment");
return extra_size;
char* extra_base;
if (file_desc != -1) {
// For file mapping, we do not call os:reserve_memory_with_fd since:
// - we later chop away parts of the mapping using os::release_memory and that could fail if the
// original mmap call had been tied to an fd.
// - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is)
// mmap but it also may System V shared memory which cannot be uncommitted as a whole, so
// chopping off and unmapping excess bits back and front (see below) would not work.
extra_base = reserve_mmapped_memory(extra_size, NULL);
if (extra_base != NULL) {
MemTracker::record_virtual_memory_reserve((address)extra_base, extra_size, CALLER_PC);
}
} else {
extra_base = os::reserve_memory(extra_size);
}
if (extra_base == NULL) {
return NULL;
} }
// After a bigger chunk was mapped, unmaps start and end parts to get the requested alignment.
static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base, size_t extra_size) {
// Do manual alignment // Do manual alignment
char* aligned_base = align_up(extra_base, alignment); char* aligned_base = align_up(extra_base, alignment);
@ -349,13 +330,39 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
os::release_memory(extra_base + begin_offset + size, end_offset); os::release_memory(extra_base + begin_offset + size, end_offset);
} }
if (file_desc != -1) { return aligned_base;
}
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
// rather than unmapping and remapping the whole chunk to get requested alignment.
char* os::reserve_memory_aligned(size_t size, size_t alignment) {
size_t extra_size = calculate_aligned_extra_size(size, alignment);
char* extra_base = os::reserve_memory(extra_size);
if (extra_base == NULL) {
return NULL;
}
return chop_extra_memory(size, alignment, extra_base, extra_size);
}
char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc) {
size_t extra_size = calculate_aligned_extra_size(size, alignment);
// For file mapping, we do not call os:map_memory_to_file(size,fd) since:
// - we later chop away parts of the mapping using os::release_memory and that could fail if the
// original mmap call had been tied to an fd.
// - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is)
// mmap but it also may System V shared memory which cannot be uncommitted as a whole, so
// chopping off and unmapping excess bits back and front (see below) would not work.
char* extra_base = reserve_mmapped_memory(extra_size, NULL);
if (extra_base == NULL) {
return NULL;
}
char* aligned_base = chop_extra_memory(size, alignment, extra_base, extra_size);
// After we have an aligned address, we can replace anonymous mapping with file mapping // After we have an aligned address, we can replace anonymous mapping with file mapping
if (replace_existing_mapping_with_file_mapping(aligned_base, size, file_desc) == NULL) { if (replace_existing_mapping_with_file_mapping(aligned_base, size, file_desc) == NULL) {
vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
} }
MemTracker::record_virtual_memory_commit((address)aligned_base, size, CALLER_PC); MemTracker::record_virtual_memory_commit((address)aligned_base, size, CALLER_PC);
}
return aligned_base; return aligned_base;
} }

View file

@ -3137,7 +3137,7 @@ void os::split_reserved_memory(char *base, size_t size, size_t split) {
// Multiple threads can race in this code but it's not possible to unmap small sections of // Multiple threads can race in this code but it's not possible to unmap small sections of
// virtual space to get requested alignment, like posix-like os's. // virtual space to get requested alignment, like posix-like os's.
// Windows prevents multiple thread from remapping over each other so this loop is thread-safe. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
assert((alignment & (os::vm_allocation_granularity() - 1)) == 0, assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
"Alignment must be a multiple of allocation granularity (page size)"); "Alignment must be a multiple of allocation granularity (page size)");
assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned"); assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
@ -3148,7 +3148,9 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
char* aligned_base = NULL; char* aligned_base = NULL;
do { do {
char* extra_base = os::reserve_memory_with_fd(extra_size, file_desc); char* extra_base = file_desc != -1 ?
os::map_memory_to_file(extra_size, file_desc) :
os::reserve_memory(extra_size);
if (extra_base == NULL) { if (extra_base == NULL) {
return NULL; return NULL;
} }
@ -3161,13 +3163,23 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
os::release_memory(extra_base, extra_size); os::release_memory(extra_base, extra_size);
} }
aligned_base = os::attempt_reserve_memory_at(aligned_base, size, file_desc); aligned_base = file_desc != -1 ?
os::attempt_map_memory_to_file_at(aligned_base, size, file_desc) :
os::attempt_reserve_memory_at(aligned_base, size);
} while (aligned_base == NULL); } while (aligned_base == NULL);
return aligned_base; return aligned_base;
} }
char* os::reserve_memory_aligned(size_t size, size_t alignment) {
return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */);
}
char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd) {
return map_or_reserve_memory_aligned(size, alignment, fd);
}
char* os::pd_reserve_memory(size_t bytes) { char* os::pd_reserve_memory(size_t bytes) {
return pd_attempt_reserve_memory_at(NULL /* addr */, bytes); return pd_attempt_reserve_memory_at(NULL /* addr */, bytes);
} }
@ -3205,7 +3217,7 @@ char* os::pd_attempt_reserve_memory_at(char* addr, size_t bytes) {
return res; return res;
} }
char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
assert(file_desc >= 0, "file_desc is not valid"); assert(file_desc >= 0, "file_desc is not valid");
return map_memory_to_file(requested_addr, bytes, file_desc); return map_memory_to_file(requested_addr, bytes, file_desc);
} }

View file

@ -220,7 +220,7 @@ static bool map_nvdimm_space(ReservedSpace rs) {
return false; return false;
} }
// commit this memory in nv-dimm // commit this memory in nv-dimm
char* ret = os::attempt_reserve_memory_at(rs.base(), rs.size(), _backing_fd); char* ret = os::attempt_map_memory_to_file_at(rs.base(), rs.size(), _backing_fd);
if (ret != rs.base()) { if (ret != rs.base()) {
if (ret != NULL) { if (ret != NULL) {

View file

@ -80,6 +80,30 @@ ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment,
_executable = executable; _executable = executable;
} }
// Helper method
static char* attempt_map_or_reserve_memory_at(char* base, size_t size, int fd) {
if (fd != -1) {
return os::attempt_map_memory_to_file_at(base, size, fd);
}
return os::attempt_reserve_memory_at(base, size);
}
// Helper method
static char* map_or_reserve_memory(size_t size, int fd) {
if (fd != -1) {
return os::map_memory_to_file(size, fd);
}
return os::reserve_memory(size);
}
// Helper method
static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fd) {
if (fd != -1) {
return os::map_memory_to_file_aligned(size, alignment, fd);
}
return os::reserve_memory_aligned(size, alignment);
}
// Helper method // Helper method
static void unmap_or_release_memory(char* base, size_t size, bool is_file_mapped) { static void unmap_or_release_memory(char* base, size_t size, bool is_file_mapped) {
if (is_file_mapped) { if (is_file_mapped) {
@ -188,13 +212,13 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
// important. If available space is not detected, return NULL. // important. If available space is not detected, return NULL.
if (requested_address != 0) { if (requested_address != 0) {
base = os::attempt_reserve_memory_at(requested_address, size, _fd_for_heap); base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap);
if (failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) { if (failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) {
// OS ignored requested address. Try different address. // OS ignored requested address. Try different address.
base = NULL; base = NULL;
} }
} else { } else {
base = os::reserve_memory_with_fd(size, _fd_for_heap); base = map_or_reserve_memory(size, _fd_for_heap);
} }
if (base == NULL) return; if (base == NULL) return;
@ -206,7 +230,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
// Make sure that size is aligned // Make sure that size is aligned
size = align_up(size, alignment); size = align_up(size, alignment);
base = os::reserve_memory_aligned(size, alignment, _fd_for_heap); base = map_or_reserve_memory_aligned(size, alignment, _fd_for_heap);
if (requested_address != 0 && if (requested_address != 0 &&
failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) { failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) {
@ -372,13 +396,13 @@ void ReservedHeapSpace::try_reserve_heap(size_t size,
} }
if (requested_address != 0) { if (requested_address != 0) {
base = os::attempt_reserve_memory_at(requested_address, size, _fd_for_heap); base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap);
} else { } else {
// Optimistically assume that the OSes returns an aligned base pointer. // Optimistically assume that the OSes returns an aligned base pointer.
// When reserving a large address range, most OSes seem to align to at // When reserving a large address range, most OSes seem to align to at
// least 64K. // least 64K.
// If the returned memory is not aligned we will release and retry. // If the returned memory is not aligned we will release and retry.
base = os::reserve_memory_with_fd(size, _fd_for_heap); base = map_or_reserve_memory(size, _fd_for_heap);
} }
} }
if (base == NULL) { return; } if (base == NULL) { return; }

View file

@ -1658,39 +1658,11 @@ char* os::reserve_memory(size_t bytes, MEMFLAGS flags) {
return result; return result;
} }
char* os::reserve_memory_with_fd(size_t bytes, int file_desc) { char* os::attempt_reserve_memory_at(char* addr, size_t bytes) {
char* result; char* result = pd_attempt_reserve_memory_at(addr, bytes);
if (file_desc != -1) {
// Could have called pd_reserve_memory() followed by replace_existing_mapping_with_file_mapping(),
// but AIX may use SHM in which case its more trouble to detach the segment and remap memory to the file.
result = os::map_memory_to_file(NULL /* addr */, bytes, file_desc);
if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit(result, bytes, CALLER_PC);
}
} else {
result = pd_reserve_memory(bytes);
if (result != NULL) {
MemTracker::record_virtual_memory_reserve(result, bytes, CALLER_PC);
}
}
return result;
}
char* os::attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc) {
char* result = NULL;
if (file_desc != -1) {
result = pd_attempt_reserve_memory_at(addr, bytes, file_desc);
if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC);
}
} else {
result = pd_attempt_reserve_memory_at(addr, bytes);
if (result != NULL) { if (result != NULL) {
MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
} }
}
return result; return result;
} }
@ -1758,6 +1730,25 @@ void os::pretouch_memory(void* start, void* end, size_t page_size) {
} }
} }
char* os::map_memory_to_file(size_t bytes, int file_desc) {
// Could have called pd_reserve_memory() followed by replace_existing_mapping_with_file_mapping(),
// but AIX may use SHM in which case its more trouble to detach the segment and remap memory to the file.
// On all current implementations NULL is interpreted as any available address.
char* result = os::map_memory_to_file(NULL /* addr */, bytes, file_desc);
if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit(result, bytes, CALLER_PC);
}
return result;
}
char* os::attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc) {
char* result = pd_attempt_map_memory_to_file_at(addr, bytes, file_desc);
if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC);
}
return result;
}
char* os::map_memory(int fd, const char* file_name, size_t file_offset, char* os::map_memory(int fd, const char* file_name, size_t file_offset,
char *addr, size_t bytes, bool read_only, char *addr, size_t bytes, bool read_only,
bool allow_exec, MEMFLAGS flags) { bool allow_exec, MEMFLAGS flags) {

View file

@ -116,7 +116,6 @@ class os: AllStatic {
static char* pd_reserve_memory(size_t bytes); static char* pd_reserve_memory(size_t bytes);
static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes); static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes);
static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc);
static bool pd_commit_memory(char* addr, size_t bytes, bool executable); static bool pd_commit_memory(char* addr, size_t bytes, bool executable);
static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint,
@ -131,6 +130,8 @@ class os: AllStatic {
static bool pd_uncommit_memory(char* addr, size_t bytes); static bool pd_uncommit_memory(char* addr, size_t bytes);
static bool pd_release_memory(char* addr, size_t bytes); static bool pd_release_memory(char* addr, size_t bytes);
static char* pd_attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc);
static char* pd_map_memory(int fd, const char* file_name, size_t file_offset, static char* pd_map_memory(int fd, const char* file_name, size_t file_offset,
char *addr, size_t bytes, bool read_only = false, char *addr, size_t bytes, bool read_only = false,
bool allow_exec = false); bool allow_exec = false);
@ -313,19 +314,14 @@ class os: AllStatic {
static int vm_allocation_granularity(); static int vm_allocation_granularity();
// Reserves virtual memory. // Reserves virtual memory.
// alignment_hint - currently only used by AIX
static char* reserve_memory(size_t bytes, MEMFLAGS flags = mtOther); static char* reserve_memory(size_t bytes, MEMFLAGS flags = mtOther);
// Reserves virtual memory.
// if file_desc != -1, also attaches the memory to the file.
static char* reserve_memory_with_fd(size_t bytes, int file_desc);
// Reserves virtual memory that starts at an address that is aligned to 'alignment'. // Reserves virtual memory that starts at an address that is aligned to 'alignment'.
static char* reserve_memory_aligned(size_t size, size_t alignment, int file_desc = -1); static char* reserve_memory_aligned(size_t size, size_t alignment);
// Attempts to reserve the virtual memory at [addr, addr + bytes). // Attempts to reserve the virtual memory at [addr, addr + bytes).
// Does not overwrite existing mappings. // Does not overwrite existing mappings.
static char* attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc = -1); static char* attempt_reserve_memory_at(char* addr, size_t bytes);
// Split a reserved memory region [base, base+size) into two regions [base, base+split) and // Split a reserved memory region [base, base+size) into two regions [base, base+split) and
// [base+split, base+size). // [base+split, base+size).
@ -370,7 +366,10 @@ class os: AllStatic {
static int create_file_for_heap(const char* dir); static int create_file_for_heap(const char* dir);
// Map memory to the file referred by fd. This function is slightly different from map_memory() // Map memory to the file referred by fd. This function is slightly different from map_memory()
// and is added to be used for implementation of -XX:AllocateHeapAt // and is added to be used for implementation of -XX:AllocateHeapAt
static char* map_memory_to_file(size_t size, int fd);
static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd);
static char* map_memory_to_file(char* base, size_t size, int fd); static char* map_memory_to_file(char* base, size_t size, int fd);
static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd);
// Replace existing reserved memory with file mapping // Replace existing reserved memory with file mapping
static char* replace_existing_mapping_with_file_mapping(char* base, size_t size, int fd); static char* replace_existing_mapping_with_file_mapping(char* base, size_t size, int fd);