7197666: java -d64 -version core dumps in a box with lots of memory
authorbrutisso
Mon, 08 Apr 2013 07:49:28 +0200
changeset 16682 4e30a46f6b76
parent 16681 d64161ca3e3c
child 16683 275523a3b451
7197666: java -d64 -version core dumps in a box with lots of memory Summary: Allow task queues to be mmapped instead of malloced on Solaris Reviewed-by: coleenp, jmasa, johnc, tschatzl
hotspot/src/share/vm/memory/allocation.hpp
hotspot/src/share/vm/memory/allocation.inline.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/utilities/taskqueue.hpp
--- a/hotspot/src/share/vm/memory/allocation.hpp	Mon Feb 11 10:31:56 2013 -0800
+++ b/hotspot/src/share/vm/memory/allocation.hpp	Mon Apr 08 07:49:28 2013 +0200
@@ -611,4 +611,23 @@
   void check()    PRODUCT_RETURN;
 };
 
+// Helper class to allocate arrays that may become large.
+// Uses the OS malloc for allocations smaller than ArrayAllocatorMallocLimit
+// and uses mapped memory for larger allocations.
+// Most OS mallocs do something similar but Solaris malloc does not revert
+// to mapped memory for large allocations. By default ArrayAllocatorMallocLimit
+// is set so that we always use malloc except for Solaris where we set the
+// limit to get mapped memory.
+template <class E, MEMFLAGS F>
+class ArrayAllocator : StackObj {
+  char* _addr;
+  bool _use_malloc;
+  size_t _size;
+ public:
+  ArrayAllocator() : _addr(NULL), _use_malloc(false), _size(0) { }
+  ~ArrayAllocator() { free(); }
+  E* allocate(size_t length);
+  void free();
+};
+
 #endif // SHARE_VM_MEMORY_ALLOCATION_HPP
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp	Mon Feb 11 10:31:56 2013 -0800
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp	Mon Apr 08 07:49:28 2013 +0200
@@ -108,5 +108,49 @@
    FreeHeap(p, F);
 }
 
+template <class E, MEMFLAGS F>
+E* ArrayAllocator<E, F>::allocate(size_t length) {
+  assert(_addr == NULL, "Already in use");
+
+  _size = sizeof(E) * length;
+  _use_malloc = _size < ArrayAllocatorMallocLimit;
+
+  if (_use_malloc) {
+    _addr = AllocateHeap(_size, F);
+    if (_addr == NULL && _size >=  (size_t)os::vm_allocation_granularity()) {
+      // malloc failed let's try with mmap instead
+      _use_malloc = false;
+    } else {
+      return (E*)_addr;
+    }
+  }
+
+  int alignment = os::vm_allocation_granularity();
+  _size = align_size_up(_size, alignment);
+
+  _addr = os::reserve_memory(_size, NULL, alignment);
+  if (_addr == NULL) {
+    vm_exit_out_of_memory(_size, "Allocator (reserve)");
+  }
+
+  bool success = os::commit_memory(_addr, _size, false /* executable */);
+  if (!success) {
+    vm_exit_out_of_memory(_size, "Allocator (commit)");
+  }
+
+  return (E*)_addr;
+}
+
+template<class E, MEMFLAGS F>
+void ArrayAllocator<E, F>::free() {
+  if (_addr != NULL) {
+    if (_use_malloc) {
+      FreeHeap(_addr, F);
+    } else {
+      os::release_memory(_addr, _size);
+    }
+    _addr = NULL;
+  }
+}
 
 #endif // SHARE_VM_MEMORY_ALLOCATION_INLINE_HPP
--- a/hotspot/src/share/vm/runtime/globals.hpp	Mon Feb 11 10:31:56 2013 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Mon Apr 08 07:49:28 2013 +0200
@@ -3668,8 +3668,13 @@
   product(bool, PrintGCCause, true,                                         \
           "Include GC cause in GC logging")                                 \
                                                                             \
-  product(bool, AllowNonVirtualCalls, false,                                \
-          "Obey the ACC_SUPER flag and allow invokenonvirtual calls")
+  product(bool , AllowNonVirtualCalls, false,                               \
+          "Obey the ACC_SUPER flag and allow invokenonvirtual calls")       \
+                                                                            \
+  experimental(uintx, ArrayAllocatorMallocLimit,                            \
+          SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx),                        \
+          "Allocation less than this value will be allocated "              \
+          "using malloc. Larger allocations will use mmap.")
 
 /*
  *  Macros for factoring of globals
--- a/hotspot/src/share/vm/utilities/taskqueue.hpp	Mon Feb 11 10:31:56 2013 -0800
+++ b/hotspot/src/share/vm/utilities/taskqueue.hpp	Mon Apr 08 07:49:28 2013 +0200
@@ -253,6 +253,7 @@
 
 template <class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE>
 class GenericTaskQueue: public TaskQueueSuper<N, F> {
+  ArrayAllocator<E, F> _array_allocator;
 protected:
   typedef typename TaskQueueSuper<N, F>::Age Age;
   typedef typename TaskQueueSuper<N, F>::idx_t idx_t;
@@ -314,7 +315,7 @@
 
 template<class E, MEMFLAGS F, unsigned int N>
 void GenericTaskQueue<E, F, N>::initialize() {
-  _elems = NEW_C_HEAP_ARRAY(E, N, F);
+  _elems = _array_allocator.allocate(N);
 }
 
 template<class E, MEMFLAGS F, unsigned int N>