< prev index next >
src/hotspot/os/linux/gc/z/zBackingFile_linux.cpp
Print this page
*** 34,43 ****
--- 34,44 ----
#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include <fcntl.h>
+ #include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <unistd.h>
*** 80,89 ****
--- 81,93 ----
// Filesystem names
#define ZFILESYSTEM_TMPFS "tmpfs"
#define ZFILESYSTEM_HUGETLBFS "hugetlbfs"
+ // Proc file entry for max map mount
+ #define ZFILENAME_PROC_MAX_MAP_COUNT "/proc/sys/vm/max_map_count"
+
// Sysfs file for transparent huge page on tmpfs
#define ZFILENAME_SHMEM_ENABLED "/sys/kernel/mm/transparent_hugepage/shmem_enabled"
// Java heap filename
#define ZFILENAME_HEAP "java_heap"
*** 276,295 ****
bool ZBackingFile::is_initialized() const {
return _initialized;
}
! int ZBackingFile::fd() const {
! return _fd;
}
! size_t ZBackingFile::size() const {
! return _size;
}
! size_t ZBackingFile::available() const {
! return _available;
}
bool ZBackingFile::is_tmpfs() const {
return _filesystem == TMPFS_MAGIC;
}
--- 280,359 ----
bool ZBackingFile::is_initialized() const {
return _initialized;
}
! void ZBackingFile::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");
! return;
! }
!
! 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 ZBackingFile::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);
! return;
! }
!
! size_t actual_max_map_count = 0;
! const int result = fscanf(file, SIZE_FORMAT, &actual_max_map_count);
! fclose(file);
! if (result != 1) {
! // Failed to read file, skip check
! log_debug(gc, init)("Failed to read %s", filename);
! return;
! }
!
! // 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 ZBackingFile::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);
! }
!
! size_t ZBackingFile::size() const {
! return _size;
}
bool ZBackingFile::is_tmpfs() const {
return _filesystem == TMPFS_MAGIC;
}
*** 570,574 ****
--- 634,657 ----
return 0;
}
return length;
}
+
+ void ZBackingFile::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 ZBackingFile::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());
+ }
+ }
< prev index next >