src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.cpp
changeset 50979 270b11dadbaf
parent 50525 767cdb97f103
child 54094 ed3c6f07faab
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.cpp	Wed Jul 04 16:49:34 2018 +0800
+++ b/src/hotspot/os_cpu/linux_x86/gc/z/zPhysicalMemoryBacking_linux_x86.cpp	Wed Jul 04 12:04:02 2018 +0200
@@ -52,8 +52,15 @@
     _file(),
     _granule_size(granule_size) {
 
-  // Check and warn if max map count seems too low
+  if (!_file.is_initialized()) {
+    return;
+  }
+
+  // Check and warn if max map count is too low
   check_max_map_count(max_capacity, granule_size);
+
+  // Check and warn if available space on filesystem is too low
+  check_available_space_on_filesystem(max_capacity);
 }
 
 void ZPhysicalMemoryBacking::check_max_map_count(size_t max_capacity, size_t granule_size) const {
@@ -61,7 +68,7 @@
   FILE* const file = fopen(filename, "r");
   if (file == NULL) {
     // Failed to open file, skip check
-    log_debug(gc)("Failed to open %s", filename);
+    log_debug(gc, init)("Failed to open %s", filename);
     return;
   }
 
@@ -70,7 +77,7 @@
   fclose(file);
   if (result != 1) {
     // Failed to read file, skip check
-    log_debug(gc)("Failed to read %s", filename);
+    log_debug(gc, init)("Failed to read %s", filename);
     return;
   }
 
@@ -81,15 +88,43 @@
   // 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 / granule_size) * 3 * 1.2;
   if (actual_max_map_count < required_max_map_count) {
-    log_warning(gc)("The system limit on number of memory mappings "
-                    "per process might be too low for the given");
-    log_warning(gc)("Java heap size (" SIZE_FORMAT "M). Please "
-                    "adjust %s to allow for at least", max_capacity / M, filename);
-    log_warning(gc)(SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). "
-                    "Continuing execution with the current limit could",
-                    required_max_map_count, actual_max_map_count);
-    log_warning(gc)("lead to a fatal error down the line, due to failed "
-                    "attempts to map memory.");
+    log_warning(gc, init)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
+    log_warning(gc, init)("The system limit on number of memory mappings per process might be too low "
+                          "for the given");
+    log_warning(gc, init)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
+                          max_capacity / M, filename);
+    log_warning(gc, init)("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, init)("limit could lead to a fatal error, due to failure to map memory.");
+  }
+}
+
+void ZPhysicalMemoryBacking::check_available_space_on_filesystem(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.
+  const size_t available = _file.available();
+  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_capacity) {
+    log_warning(gc, init)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
+    log_warning(gc, init)("Not enough space available on the backing filesystem to hold the current "
+                          "max Java heap");
+    log_warning(gc, init)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem "
+                          "accordingly (available", max_capacity / M);
+    log_warning(gc, init)("space is currently " SIZE_FORMAT "M). Continuing execution with the current "
+                          "filesystem size could", available / M);
+    log_warning(gc, init)("lead to a premature OutOfMemoryError being thrown, due to failure to map "
+                          "memory.");
   }
 }
 
@@ -97,18 +132,16 @@
   return _file.is_initialized();
 }
 
-bool ZPhysicalMemoryBacking::expand(size_t from, size_t to) {
-  const size_t size = to - from;
+size_t ZPhysicalMemoryBacking::try_expand(size_t old_capacity, size_t new_capacity) {
+  assert(old_capacity < new_capacity, "Invalid old/new capacity");
 
-  // Expand
-  if (!_file.expand(from, size)) {
-    return false;
+  const size_t capacity = _file.try_expand(old_capacity, new_capacity - old_capacity, _granule_size);
+  if (capacity > old_capacity) {
+    // Add expanded capacity to free list
+    _manager.free(old_capacity, capacity - old_capacity);
   }
 
-  // Add expanded space to free list
-  _manager.free(from, size);
-
-  return true;
+  return capacity;
 }
 
 ZPhysicalMemory ZPhysicalMemoryBacking::alloc(size_t size) {