changeset 4419:754c24457b20

7112912: Message "Error occurred during initialization of VM" on boxes with lots of RAM Summary: Ergonomics now also takes available virtual memory into account when deciding for a heap size. The helper method to determine the maximum allocatable memory block now uses the appropriate OS specific calls to retrieve available virtual memory for the java process. In 32 bit environments this method now also searches for the maximum actually reservable amount of memory. Merge previously separate implementations for Linux/BSD/Solaris into a single method. Reviewed-by: jmasa, tamao
author tschatzl
date Wed, 27 Mar 2013 19:21:18 +0100
parents 2e093b564241
children 24ef5fb05e0f
files src/os/bsd/vm/os_bsd.cpp src/os/linux/vm/os_linux.cpp src/os/posix/vm/os_posix.cpp src/os/solaris/vm/os_solaris.cpp src/os/windows/vm/os_windows.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/arguments.hpp src/share/vm/runtime/globals.hpp src/share/vm/runtime/os.hpp
diffstat 9 files changed, 92 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/bsd/vm/os_bsd.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/os/bsd/vm/os_bsd.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -167,20 +167,6 @@
   return Bsd::physical_memory();
 }
 
-julong os::allocatable_physical_memory(julong size) {
-#ifdef _LP64
-  return size;
-#else
-  julong result = MIN2(size, (julong)3800*M);
-   if (!is_allocatable(result)) {
-     // See comments under solaris for alignment considerations
-     julong reasonable_size = (julong)2*G - 2 * os::vm_page_size();
-     result =  MIN2(size, reasonable_size);
-   }
-   return result;
-#endif // _LP64
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // environment support
 
--- a/src/os/linux/vm/os_linux.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/os/linux/vm/os_linux.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -194,20 +194,6 @@
   return Linux::physical_memory();
 }
 
-julong os::allocatable_physical_memory(julong size) {
-#ifdef _LP64
-  return size;
-#else
-  julong result = MIN2(size, (julong)3800*M);
-   if (!is_allocatable(result)) {
-     // See comments under solaris for alignment considerations
-     julong reasonable_size = (julong)2*G - 2 * os::vm_page_size();
-     result =  MIN2(size, reasonable_size);
-   }
-   return result;
-#endif // _LP64
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // environment support
 
--- a/src/os/posix/vm/os_posix.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/os/posix/vm/os_posix.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -188,4 +188,66 @@
   st->cr();
 }
 
+bool os::has_allocatable_memory_limit(julong* limit) {
+  struct rlimit rlim;
+  int getrlimit_res = getrlimit(RLIMIT_AS, &rlim);
+  // if there was an error when calling getrlimit, assume that there is no limitation
+  // on virtual memory.
+  bool result;
+  if ((getrlimit_res != 0) || (rlim.rlim_cur == RLIM_INFINITY)) {
+    result = false;
+  } else {
+    *limit = (julong)rlim.rlim_cur;
+    result = true;
+  }
+#ifdef _LP64
+  return result;
+#else
+  // arbitrary virtual space limit for 32 bit Unices found by testing. If
+  // getrlimit above returned a limit, bound it with this limit. Otherwise
+  // directly use it.
+  const julong max_virtual_limit = (julong)3800*M;
+  if (result) {
+    *limit = MIN2(*limit, max_virtual_limit);
+  } else {
+    *limit = max_virtual_limit;
+  }
 
+  // bound by actually allocatable memory. The algorithm uses two bounds, an
+  // upper and a lower limit. The upper limit is the current highest amount of
+  // memory that could not be allocated, the lower limit is the current highest
+  // amount of memory that could be allocated.
+  // The algorithm iteratively refines the result by halving the difference
+  // between these limits, updating either the upper limit (if that value could
+  // not be allocated) or the lower limit (if the that value could be allocated)
+  // until the difference between these limits is "small".
+
+  // the minimum amount of memory we care about allocating.
+  const julong min_allocation_size = M;
+
+  julong upper_limit = *limit;
+
+  // first check a few trivial cases
+  if (is_allocatable(upper_limit) || (upper_limit <= min_allocation_size)) {
+    *limit = upper_limit;
+  } else if (!is_allocatable(min_allocation_size)) {
+    // we found that not even min_allocation_size is allocatable. Return it
+    // anyway. There is no point to search for a better value any more.
+    *limit = min_allocation_size;
+  } else {
+    // perform the binary search.
+    julong lower_limit = min_allocation_size;
+    while ((upper_limit - lower_limit) > min_allocation_size) {
+      julong temp_limit = ((upper_limit - lower_limit) / 2) + lower_limit;
+      temp_limit = align_size_down_(temp_limit, min_allocation_size);
+      if (is_allocatable(temp_limit)) {
+        lower_limit = temp_limit;
+      } else {
+        upper_limit = temp_limit;
+      }
+    }
+    *limit = lower_limit;
+  }
+  return true;
+#endif
+}
--- a/src/os/solaris/vm/os_solaris.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/os/solaris/vm/os_solaris.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -476,24 +476,6 @@
    return Solaris::physical_memory();
 }
 
-julong os::allocatable_physical_memory(julong size) {
-#ifdef _LP64
-   return size;
-#else
-   julong result = MIN2(size, (julong)3835*M);
-   if (!is_allocatable(result)) {
-     // Memory allocations will be aligned but the alignment
-     // is not known at this point.  Alignments will
-     // be at most to LargePageSizeInBytes.  Protect
-     // allocations from alignments up to illegal
-     // values. If at this point 2G is illegal.
-     julong reasonable_size = (julong)2*G - 2 * LargePageSizeInBytes;
-     result =  MIN2(size, reasonable_size);
-   }
-   return result;
-#endif
-}
-
 static hrtime_t first_hrtime = 0;
 static const hrtime_t hrtime_hz = 1000*1000*1000;
 const int LOCK_BUSY = 1;
--- a/src/os/windows/vm/os_windows.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/os/windows/vm/os_windows.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -686,12 +686,17 @@
   return win32::physical_memory();
 }
 
-julong os::allocatable_physical_memory(julong size) {
+bool os::has_allocatable_memory_limit(julong* limit) {
+  MEMORYSTATUSEX ms;
+  ms.dwLength = sizeof(ms);
+  GlobalMemoryStatusEx(&ms);
 #ifdef _LP64
-  return size;
+  *limit = (julong)ms.ullAvailVirtual;
+  return true;
 #else
   // Limit to 1400m because of the 2gb address space wall
-  return MIN2(size, (julong)1400*M);
+  *limit = MIN2((julong)1400*M, (julong)ms.ullAvailVirtual);
+  return true;
 #endif
 }
 
--- a/src/share/vm/runtime/arguments.cpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/share/vm/runtime/arguments.cpp	Wed Mar 27 19:21:18 2013 +0100
@@ -1552,6 +1552,15 @@
   }
 }
 
+julong Arguments::limit_by_allocatable_memory(julong limit) {
+  julong max_allocatable;
+  julong result = limit;
+  if (os::has_allocatable_memory_limit(&max_allocatable)) {
+    result = MIN2(result, max_allocatable / MaxVirtMemFraction);
+  }
+  return result;
+}
+
 void Arguments::set_heap_size() {
   if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) {
     // Deprecated flag
@@ -1590,12 +1599,12 @@
       }
       reasonable_max = MIN2(reasonable_max, max_coop_heap);
     }
-    reasonable_max = os::allocatable_physical_memory(reasonable_max);
+    reasonable_max = limit_by_allocatable_memory(reasonable_max);
 
     if (!FLAG_IS_DEFAULT(InitialHeapSize)) {
       // An initial heap size was specified on the command line,
       // so be sure that the maximum size is consistent.  Done
-      // after call to allocatable_physical_memory because that
+      // after call to limit_by_allocatable_memory because that
       // method might reduce the allocation size.
       reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
     }
@@ -1615,14 +1624,14 @@
 
     reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);
 
-    reasonable_minimum = os::allocatable_physical_memory(reasonable_minimum);
+    reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum);
 
     julong reasonable_initial = phys_mem / InitialRAMFraction;
 
     reasonable_initial = MAX2(reasonable_initial, reasonable_minimum);
     reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
 
-    reasonable_initial = os::allocatable_physical_memory(reasonable_initial);
+    reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
 
     if (PrintGCDetails && Verbose) {
       // Cannot use gclog_or_tty yet.
@@ -2608,9 +2617,7 @@
       initHeapSize = MIN2(total_memory / (julong)2,
                           total_memory - (julong)160*M);
 
-      // Make sure that if we have a lot of memory we cap the 32 bit
-      // process space.  The 64bit VM version of this function is a nop.
-      initHeapSize = os::allocatable_physical_memory(initHeapSize);
+      initHeapSize = limit_by_allocatable_memory(initHeapSize);
 
       if (FLAG_IS_DEFAULT(MaxHeapSize)) {
          FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize);
--- a/src/share/vm/runtime/arguments.hpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/share/vm/runtime/arguments.hpp	Wed Mar 27 19:21:18 2013 +0100
@@ -312,6 +312,9 @@
   static void set_use_compressed_oops();
   static void set_ergonomics_flags();
   static void set_shared_spaces_flags();
+  // limits the given memory size by the maximum amount of memory this process is
+  // currently allowed to allocate or reserve.
+  static julong limit_by_allocatable_memory(julong size);
   // Setup heap size
   static void set_heap_size();
   // Based on automatic selection criteria, should the
--- a/src/share/vm/runtime/globals.hpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/share/vm/runtime/globals.hpp	Wed Mar 27 19:21:18 2013 +0100
@@ -1962,6 +1962,10 @@
   product(uintx, InitialRAMFraction, 64,                                    \
           "Fraction (1/n) of real memory used for initial heap size")       \
                                                                             \
+  develop(uintx, MaxVirtMemFraction, 2,                                     \
+          "Maximum fraction (1/n) of virtual memory used for ergonomically" \
+          "determining maximum heap size")                                  \
+                                                                            \
   product(bool, UseAutoGCSelectPolicy, false,                               \
           "Use automatic collection selection policy")                      \
                                                                             \
--- a/src/share/vm/runtime/os.hpp	Thu Mar 28 10:27:28 2013 +0100
+++ b/src/share/vm/runtime/os.hpp	Wed Mar 27 19:21:18 2013 +0100
@@ -184,7 +184,7 @@
   }
   static julong available_memory();
   static julong physical_memory();
-  static julong allocatable_physical_memory(julong size);
+  static bool has_allocatable_memory_limit(julong* limit);
   static bool is_server_class_machine();
 
   // number of CPUs