hotspot/src/share/vm/memory/allocation.cpp
changeset 13195 be27e1b6a4b9
parent 10565 dc90c239f4ec
child 13728 882756847a04
--- a/hotspot/src/share/vm/memory/allocation.cpp	Wed Jun 27 15:23:36 2012 +0200
+++ b/hotspot/src/share/vm/memory/allocation.cpp	Thu Jun 28 17:03:16 2012 -0400
@@ -26,10 +26,13 @@
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/os.hpp"
 #include "runtime/task.hpp"
 #include "runtime/threadCritical.hpp"
+#include "services/memTracker.hpp"
 #include "utilities/ostream.hpp"
+
 #ifdef TARGET_OS_FAMILY_linux
 # include "os_linux.inline.hpp"
 #endif
@@ -43,32 +46,16 @@
 # include "os_bsd.inline.hpp"
 #endif
 
-void* CHeapObj::operator new(size_t size){
-  return (void *) AllocateHeap(size, "CHeapObj-new");
-}
-
-void* CHeapObj::operator new (size_t size, const std::nothrow_t&  nothrow_constant) {
-  char* p = (char*) os::malloc(size);
-#ifdef ASSERT
-  if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
-#endif
-  return p;
-}
-
-void CHeapObj::operator delete(void* p){
- FreeHeap(p);
-}
-
 void* StackObj::operator new(size_t size)  { ShouldNotCallThis(); return 0; };
 void  StackObj::operator delete(void* p)   { ShouldNotCallThis(); };
 void* _ValueObj::operator new(size_t size)  { ShouldNotCallThis(); return 0; };
 void  _ValueObj::operator delete(void* p)   { ShouldNotCallThis(); };
 
-void* ResourceObj::operator new(size_t size, allocation_type type) {
+void* ResourceObj::operator new(size_t size, allocation_type type, MEMFLAGS flags) {
   address res;
   switch (type) {
    case C_HEAP:
-    res = (address)AllocateHeap(size, "C_Heap: ResourceOBJ");
+    res = (address)AllocateHeap(size, flags, CALLER_PC);
     DEBUG_ONLY(set_allocation_type(res, C_HEAP);)
     break;
    case RESOURCE_AREA:
@@ -184,7 +171,7 @@
 
 // MT-safe pool of chunks to reduce malloc/free thrashing
 // NB: not using Mutex because pools are used before Threads are initialized
-class ChunkPool {
+class ChunkPool: public CHeapObj<mtInternal> {
   Chunk*       _first;        // first cached Chunk; its first word points to next chunk
   size_t       _num_chunks;   // number of unused chunks in pool
   size_t       _num_used;     // number of chunks currently checked out
@@ -210,14 +197,16 @@
    ChunkPool(size_t size) : _size(size) { _first = NULL; _num_chunks = _num_used = 0; }
 
   // Allocate a new chunk from the pool (might expand the pool)
-  void* allocate(size_t bytes) {
+  _NOINLINE_ void* allocate(size_t bytes) {
     assert(bytes == _size, "bad size");
     void* p = NULL;
+    // No VM lock can be taken inside ThreadCritical lock, so os::malloc
+    // should be done outside ThreadCritical lock due to NMT
     { ThreadCritical tc;
       _num_used++;
       p = get_first();
-      if (p == NULL) p = os::malloc(bytes);
     }
+    if (p == NULL) p = os::malloc(bytes, mtChunk, CURRENT_PC);
     if (p == NULL)
       vm_exit_out_of_memory(bytes, "ChunkPool::allocate");
 
@@ -238,28 +227,34 @@
 
   // Prune the pool
   void free_all_but(size_t n) {
+    Chunk* cur = NULL;
+    Chunk* next;
+    {
     // if we have more than n chunks, free all of them
     ThreadCritical tc;
     if (_num_chunks > n) {
       // free chunks at end of queue, for better locality
-      Chunk* cur = _first;
+        cur = _first;
       for (size_t i = 0; i < (n - 1) && cur != NULL; i++) cur = cur->next();
 
       if (cur != NULL) {
-        Chunk* next = cur->next();
+          next = cur->next();
         cur->set_next(NULL);
         cur = next;
 
-        // Free all remaining chunks
+          _num_chunks = n;
+        }
+      }
+    }
+
+    // Free all remaining chunks, outside of ThreadCritical
+    // to avoid deadlock with NMT
         while(cur != NULL) {
           next = cur->next();
-          os::free(cur);
-          _num_chunks--;
+      os::free(cur, mtChunk);
           cur = next;
         }
       }
-    }
-  }
 
   // Accessors to preallocated pool's
   static ChunkPool* large_pool()  { assert(_large_pool  != NULL, "must be initialized"); return _large_pool;  }
@@ -323,7 +318,7 @@
    case Chunk::medium_size: return ChunkPool::medium_pool()->allocate(bytes);
    case Chunk::init_size:   return ChunkPool::small_pool()->allocate(bytes);
    default: {
-     void *p =  os::malloc(bytes);
+     void *p =  os::malloc(bytes, mtChunk, CALLER_PC);
      if (p == NULL)
        vm_exit_out_of_memory(bytes, "Chunk::new");
      return p;
@@ -337,7 +332,7 @@
    case Chunk::size:        ChunkPool::large_pool()->free(c); break;
    case Chunk::medium_size: ChunkPool::medium_pool()->free(c); break;
    case Chunk::init_size:   ChunkPool::small_pool()->free(c); break;
-   default:                 os::free(c);
+   default:                 os::free(c, mtChunk);
   }
 }
 
@@ -374,6 +369,7 @@
 }
 
 //------------------------------Arena------------------------------------------
+NOT_PRODUCT(volatile jint Arena::_instance_count = 0;)
 
 Arena::Arena(size_t init_size) {
   size_t round_size = (sizeof (char *)) - 1;
@@ -382,6 +378,7 @@
   _hwm = _chunk->bottom();      // Save the cached hwm, max
   _max = _chunk->top();
   set_size_in_bytes(init_size);
+  NOT_PRODUCT(Atomic::inc(&_instance_count);)
 }
 
 Arena::Arena() {
@@ -389,12 +386,15 @@
   _hwm = _chunk->bottom();      // Save the cached hwm, max
   _max = _chunk->top();
   set_size_in_bytes(Chunk::init_size);
+  NOT_PRODUCT(Atomic::inc(&_instance_count);)
 }
 
 Arena::Arena(Arena *a) : _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) {
   set_size_in_bytes(a->size_in_bytes());
+  NOT_PRODUCT(Atomic::inc(&_instance_count);)
 }
 
+
 Arena *Arena::move_contents(Arena *copy) {
   copy->destruct_contents();
   copy->_chunk = _chunk;
@@ -409,6 +409,42 @@
 
 Arena::~Arena() {
   destruct_contents();
+  NOT_PRODUCT(Atomic::dec(&_instance_count);)
+}
+
+void* Arena::operator new(size_t size) {
+  assert(false, "Use dynamic memory type binding");
+  return NULL;
+}
+
+void* Arena::operator new (size_t size, const std::nothrow_t&  nothrow_constant) {
+  assert(false, "Use dynamic memory type binding");
+  return NULL;
+}
+
+  // dynamic memory type binding
+void* Arena::operator new(size_t size, MEMFLAGS flags) {
+#ifdef ASSERT
+  void* p = (void*)AllocateHeap(size, flags|otArena, CALLER_PC);
+  if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
+  return p;
+#else
+  return (void *) AllocateHeap(size, flags|otArena, CALLER_PC);
+#endif
+}
+
+void* Arena::operator new(size_t size, const std::nothrow_t& nothrow_constant, MEMFLAGS flags) {
+#ifdef ASSERT
+  void* p = os::malloc(size, flags|otArena, CALLER_PC);
+  if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
+  return p;
+#else
+  return os::malloc(size, flags|otArena, CALLER_PC);
+#endif
+}
+
+void Arena::operator delete(void* p) {
+  FreeHeap(p);
 }
 
 // Destroy this arenas contents and reset to empty
@@ -421,6 +457,14 @@
   reset();
 }
 
+// This is high traffic method, but many calls actually don't
+// change the size
+void Arena::set_size_in_bytes(size_t size) {
+  if (_size_in_bytes != size) {
+    _size_in_bytes = size;
+    MemTracker::record_arena_size((address)this, size);
+  }
+}
 
 // Total of all Chunks in arena
 size_t Arena::used() const {
@@ -448,7 +492,6 @@
   if (_chunk == NULL) {
     signal_out_of_memory(len * Chunk::aligned_overhead_size(), "Arena::grow");
   }
-
   if (k) k->set_next(_chunk);   // Append new chunk to end of linked list
   else _first = _chunk;
   _hwm  = _chunk->bottom();     // Save the cached hwm, max
@@ -538,7 +581,7 @@
   assert(UseMallocOnly, "shouldn't call");
   // use malloc, but save pointer in res. area for later freeing
   char** save = (char**)internal_malloc_4(sizeof(char*));
-  return (*save = (char*)os::malloc(size));
+  return (*save = (char*)os::malloc(size, mtChunk));
 }
 
 // for debugging with UseMallocOnly