< prev index next >

src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp

Print this page

        

*** 297,307 **** bool ZPhysicalMemoryBacking::is_initialized() const { return _initialized; } ! void ZPhysicalMemoryBacking::warn_available_space(size_t max) const { // Note that the available space on a tmpfs or a hugetlbfs filesystem // will be zero if no size limit was specified when it was mounted. if (_available == 0) { // No size limit set, skip check log_info(gc, init)("Available space on backing filesystem: N/A"); --- 297,307 ---- bool ZPhysicalMemoryBacking::is_initialized() const { return _initialized; } ! void ZPhysicalMemoryBacking::warn_available_space(size_t max_capacity) const { // Note that the available space on a tmpfs or a hugetlbfs filesystem // will be zero if no size limit was specified when it was mounted. if (_available == 0) { // No size limit set, skip check log_info(gc, init)("Available space on backing filesystem: N/A");
*** 311,332 **** log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M); // Warn if the filesystem doesn't currently have enough space available to hold // the max heap size. The max heap size will be capped if we later hit this limit // when trying to expand the heap. ! if (_available < max) { log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap"); log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly " ! "(available", max / M); log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem " "size could", _available / M); ! log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory."); } } ! void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const { const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT; FILE* const file = fopen(filename, "r"); if (file == NULL) { // Failed to open file, skip check log_debug(gc, init)("Failed to open %s", filename); --- 311,332 ---- log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", _available / M); // Warn if the filesystem doesn't currently have enough space available to hold // the max heap size. The max heap size will be capped if we later hit this limit // when trying to expand the heap. ! if (_available < max_capacity) { log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap"); log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly " ! "(available", max_capacity / M); log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem " "size could", _available / M); ! log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to commit memory."); } } ! void ZPhysicalMemoryBacking::warn_max_map_count(size_t max_capacity) const { const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT; FILE* const file = fopen(filename, "r"); if (file == NULL) { // Failed to open file, skip check log_debug(gc, init)("Failed to open %s", filename);
*** 345,372 **** // The required max map count is impossible to calculate exactly since subsystems // other than ZGC are also creating memory mappings, and we have no control over that. // However, ZGC tends to create the most mappings and dominate the total count. // In the worst cases, ZGC will map each granule three times, i.e. once per heap view. // We speculate that we need another 20% to allow for non-ZGC subsystems to map memory. ! const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2; if (actual_max_map_count < required_max_map_count) { log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given"); log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at", ! max / M, filename); log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution " "with the current", required_max_map_count, actual_max_map_count); ! log_warning(gc)("limit could lead to a fatal error, due to failure to map memory."); } } ! void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const { // Warn if available space is too low ! warn_available_space(max); // Warn if max map count is too low ! warn_max_map_count(max); } bool ZPhysicalMemoryBacking::is_tmpfs() const { return _filesystem == TMPFS_MAGIC; } --- 345,372 ---- // The required max map count is impossible to calculate exactly since subsystems // other than ZGC are also creating memory mappings, and we have no control over that. // However, ZGC tends to create the most mappings and dominate the total count. // In the worst cases, ZGC will map each granule three times, i.e. once per heap view. // We speculate that we need another 20% to allow for non-ZGC subsystems to map memory. ! const size_t required_max_map_count = (max_capacity / ZGranuleSize) * 3 * 1.2; if (actual_max_map_count < required_max_map_count) { log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****"); log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given"); log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at", ! max_capacity / M, filename); log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution " "with the current", required_max_map_count, actual_max_map_count); ! log_warning(gc)("limit could lead to a premature OutOfMemoryError being thrown, due to failure to map memory."); } } ! void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const { // Warn if available space is too low ! warn_available_space(max_capacity); // Warn if max map count is too low ! warn_max_map_count(max_capacity); } bool ZPhysicalMemoryBacking::is_tmpfs() const { return _filesystem == TMPFS_MAGIC; }
*** 472,482 **** // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(size_t offset, size_t length) { // fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs // since Linux 4.3. When fallocate(2) is not supported we emulate it using // mmap/munmap (for hugetlbfs and tmpfs with transparent huge pages) or pwrite // (for tmpfs without transparent huge pages and other filesystem types). if (ZLargePages::is_explicit()) { --- 472,482 ---- // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_compat(size_t offset, size_t length) const { // fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs // since Linux 4.3. When fallocate(2) is not supported we emulate it using // mmap/munmap (for hugetlbfs and tmpfs with transparent huge pages) or pwrite // (for tmpfs without transparent huge pages and other filesystem types). if (ZLargePages::is_explicit()) {
*** 486,496 **** } else { return fallocate_compat_pwrite(offset, length); } } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t length) { const int mode = 0; // Allocate const int res = ZSyscall::fallocate(_fd, mode, offset, length); if (res == -1) { // Failed return errno; --- 486,496 ---- } else { return fallocate_compat_pwrite(offset, length); } } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole_syscall(size_t offset, size_t length) const { const int mode = 0; // Allocate const int res = ZSyscall::fallocate(_fd, mode, offset, length); if (res == -1) { // Failed return errno;
*** 498,508 **** // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length) { // Using compat mode is more efficient when allocating space on hugetlbfs. // Note that allocating huge pages this way will only reserve them, and not // associate them with segments of the file. We must guarantee that we at // some point touch these segments, otherwise we can not punch hole in them. // Also note that we need to use compat mode when using transparent huge pages, --- 498,508 ---- // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate_fill_hole(size_t offset, size_t length) const { // Using compat mode is more efficient when allocating space on hugetlbfs. // Note that allocating huge pages this way will only reserve them, and not // associate them with segments of the file. We must guarantee that we at // some point touch these segments, otherwise we can not punch hole in them. // Also note that we need to use compat mode when using transparent huge pages,
*** 525,535 **** } return fallocate_fill_hole_compat(offset, length); } ! ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length) { if (ZLargePages::is_explicit()) { // We can only punch hole in pages that have been touched. Non-touched // pages are only reserved, and not associated with any specific file // segment. We don't know which pages have been previously touched, so // we always touch them here to guarantee that we can punch hole. --- 525,535 ---- } return fallocate_fill_hole_compat(offset, length); } ! ZErrno ZPhysicalMemoryBacking::fallocate_punch_hole(size_t offset, size_t length) const { if (ZLargePages::is_explicit()) { // We can only punch hole in pages that have been touched. Non-touched // pages are only reserved, and not associated with any specific file // segment. We don't know which pages have been previously touched, so // we always touch them here to guarantee that we can punch hole.
*** 548,558 **** // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offset, size_t length) { // Try first half const size_t offset0 = offset; const size_t length0 = align_up(length / 2, _block_size); const ZErrno err0 = fallocate(punch_hole, offset0, length0); if (err0) { --- 548,558 ---- // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::split_and_fallocate(bool punch_hole, size_t offset, size_t length) const { // Try first half const size_t offset0 = offset; const size_t length0 = align_up(length / 2, _block_size); const ZErrno err0 = fallocate(punch_hole, offset0, length0); if (err0) {
*** 569,579 **** // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t length) { assert(is_aligned(offset, _block_size), "Invalid offset"); assert(is_aligned(length, _block_size), "Invalid length"); const ZErrno err = punch_hole ? fallocate_punch_hole(offset, length) : fallocate_fill_hole(offset, length); if (err == EINTR && length > _block_size) { --- 569,579 ---- // Success return 0; } ! ZErrno ZPhysicalMemoryBacking::fallocate(bool punch_hole, size_t offset, size_t length) const { assert(is_aligned(offset, _block_size), "Invalid offset"); assert(is_aligned(length, _block_size), "Invalid length"); const ZErrno err = punch_hole ? fallocate_punch_hole(offset, length) : fallocate_fill_hole(offset, length); if (err == EINTR && length > _block_size) {
*** 585,595 **** } return err; } ! bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) { log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", offset / M, (offset + length) / M, length / M); retry: const ZErrno err = fallocate(false /* punch_hole */, offset, length); --- 585,595 ---- } return err; } ! bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const { log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", offset / M, (offset + length) / M, length / M); retry: const ZErrno err = fallocate(false /* punch_hole */, offset, length);
*** 622,632 **** const GrowableArray<int>* mapping = os::Linux::numa_nindex_to_node(); const size_t nindex = (offset >> ZGranuleSizeShift) % mapping->length(); return mapping->at((int)nindex); } ! size_t ZPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t length) { size_t committed = 0; // Commit one granule at a time, so that each granule // can be allocated from a different preferred node. while (committed < length) { --- 622,632 ---- const GrowableArray<int>* mapping = os::Linux::numa_nindex_to_node(); const size_t nindex = (offset >> ZGranuleSizeShift) % mapping->length(); return mapping->at((int)nindex); } ! size_t ZPhysicalMemoryBacking::commit_numa_interleaved(size_t offset, size_t length) const { size_t committed = 0; // Commit one granule at a time, so that each granule // can be allocated from a different preferred node. while (committed < length) {
*** 647,657 **** os::Linux::numa_set_preferred(-1); return committed; } ! size_t ZPhysicalMemoryBacking::commit_default(size_t offset, size_t length) { // Try to commit the whole region if (commit_inner(offset, length)) { // Success return length; } --- 647,657 ---- os::Linux::numa_set_preferred(-1); return committed; } ! size_t ZPhysicalMemoryBacking::commit_default(size_t offset, size_t length) const { // Try to commit the whole region if (commit_inner(offset, length)) { // Success return length; }
*** 675,695 **** end -= length; } } } ! size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) { if (ZNUMA::is_enabled() && !ZLargePages::is_explicit()) { // To get granule-level NUMA interleaving when using non-large pages, // we must explicitly interleave the memory at commit/fallocate time. return commit_numa_interleaved(offset, length); } return commit_default(offset, length); } ! size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) { log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", offset / M, (offset + length) / M, length / M); const ZErrno err = fallocate(true /* punch_hole */, offset, length); if (err) { --- 675,695 ---- end -= length; } } } ! size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) const { if (ZNUMA::is_enabled() && !ZLargePages::is_explicit()) { // To get granule-level NUMA interleaving when using non-large pages, // we must explicitly interleave the memory at commit/fallocate time. return commit_numa_interleaved(offset, length); } return commit_default(offset, length); } ! size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const { log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)", offset / M, (offset + length) / M, length / M); const ZErrno err = fallocate(true /* punch_hole */, offset, length); if (err) {
*** 698,720 **** } return length; } ! void ZPhysicalMemoryBacking::map(uintptr_t addr, size_t size, uintptr_t offset) const { const void* const res = mmap((void*)addr, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _fd, offset); if (res == MAP_FAILED) { ZErrno err; ! fatal("Failed to map memory (%s)", err.to_string()); } } void ZPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const { // Note that we must keep the address space reservation intact and just detach // the backing memory. For this reason we map a new anonymous, non-accessible // and non-reserved page over the mapping instead of actually unmapping. const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); if (res == MAP_FAILED) { ZErrno err; ! fatal("Failed to map memory (%s)", err.to_string()); } } --- 698,723 ---- } return length; } ! bool ZPhysicalMemoryBacking::map(uintptr_t addr, size_t size, uintptr_t offset) const { const void* const res = mmap((void*)addr, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _fd, offset); if (res == MAP_FAILED) { ZErrno err; ! log_error(gc)("Failed to map memory (%s)", err.to_string()); ! return false; } + + return true; } void ZPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const { // Note that we must keep the address space reservation intact and just detach // the backing memory. For this reason we map a new anonymous, non-accessible // and non-reserved page over the mapping instead of actually unmapping. const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); if (res == MAP_FAILED) { ZErrno err; ! log_error(gc)("Failed to map memory (%s)", err.to_string()); } }
< prev index next >