8207200: Committed > max memory usage when getting MemoryUsage
authortschatzl
Tue, 04 Sep 2018 12:18:35 +0200
changeset 51625 c265860d5d45
parent 51624 7ed777a14094
child 51626 0514d4c30cf1
8207200: Committed > max memory usage when getting MemoryUsage Summary: Make sure that modification of memory usage variables are synchronized with returning them to Java. Reviewed-by: sangheki, mchung
src/hotspot/share/gc/g1/g1CollectedHeap.cpp
src/hotspot/share/gc/g1/g1CollectedHeap.hpp
src/hotspot/share/gc/g1/g1MemoryPool.cpp
src/hotspot/share/gc/g1/g1MonitoringSupport.cpp
src/hotspot/share/gc/g1/g1MonitoringSupport.hpp
src/hotspot/share/gc/shared/collectedHeap.cpp
src/hotspot/share/gc/shared/collectedHeap.hpp
src/hotspot/share/runtime/mutexLocker.cpp
src/hotspot/share/runtime/mutexLocker.hpp
src/hotspot/share/services/management.cpp
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -4654,6 +4654,10 @@
   _g1mm->initialize_serviceability();
 }
 
+MemoryUsage G1CollectedHeap::memory_usage() {
+  return _g1mm->memory_usage();
+}
+
 GrowableArray<GCMemoryManager*> G1CollectedHeap::memory_managers() {
   return _g1mm->memory_managers();
 }
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Tue Sep 04 12:18:35 2018 +0200
@@ -961,6 +961,7 @@
   virtual SoftRefPolicy* soft_ref_policy();
 
   virtual void initialize_serviceability();
+  virtual MemoryUsage memory_usage();
   virtual GrowableArray<GCMemoryManager*> memory_managers();
   virtual GrowableArray<MemoryPool*> memory_pools();
 
--- a/src/hotspot/share/gc/g1/g1MemoryPool.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1MemoryPool.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -48,9 +48,7 @@
                     false /* support_usage_threshold */) { }
 
 MemoryUsage G1EdenPool::get_memory_usage() {
-  size_t committed  = _g1mm->eden_space_committed();
-
-  return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size());
+  return _g1mm->eden_space_memory_usage(initial_size(), max_size());
 }
 
 G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h, size_t initial_size) :
@@ -61,9 +59,7 @@
                     false /* support_usage_threshold */) { }
 
 MemoryUsage G1SurvivorPool::get_memory_usage() {
-  size_t committed  = _g1mm->survivor_space_committed();
-
-  return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size());
+  return _g1mm->survivor_space_memory_usage(initial_size(), max_size());
 }
 
 G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h, size_t initial_size, size_t max_size) :
@@ -74,7 +70,5 @@
                     true /* support_usage_threshold */) { }
 
 MemoryUsage G1OldGenPool::get_memory_usage() {
-  size_t committed  = _g1mm->old_gen_committed();
-
-  return MemoryUsage(initial_size(), used_in_bytes(), committed, max_size());
+  return _g1mm->old_gen_memory_usage(initial_size(), max_size());
 }
--- a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -202,6 +202,11 @@
   _incremental_memory_manager.add_pool(_old_gen_pool, false /* always_affected_by_gc */);
 }
 
+MemoryUsage G1MonitoringSupport::memory_usage() {
+  MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
+  return MemoryUsage(InitialHeapSize, _overall_used, _overall_committed, _g1h->max_capacity());
+}
+
 GrowableArray<GCMemoryManager*> G1MonitoringSupport::memory_managers() {
   GrowableArray<GCMemoryManager*> memory_managers(2);
   memory_managers.append(&_incremental_memory_manager);
@@ -220,6 +225,7 @@
 void G1MonitoringSupport::recalculate_sizes() {
   assert_heap_locked_or_at_safepoint(true);
 
+  MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
   // Recalculate all the sizes from scratch.
 
   uint young_list_length = _g1h->young_regions_count();
@@ -296,13 +302,41 @@
 }
 
 void G1MonitoringSupport::update_eden_size() {
-  // Recalculate everything - this is fast enough.
+  // Recalculate everything - this should be fast enough and we are sure that we do not
+  // miss anything.
   recalculate_sizes();
   if (UsePerfData) {
     _eden_space_counters->update_used(_eden_space_used);
   }
 }
 
+MemoryUsage G1MonitoringSupport::eden_space_memory_usage(size_t initial_size, size_t max_size) {
+  MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
+
+  return MemoryUsage(initial_size,
+                     _eden_space_used,
+                     _eden_space_committed,
+                     max_size);
+}
+
+MemoryUsage G1MonitoringSupport::survivor_space_memory_usage(size_t initial_size, size_t max_size) {
+  MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
+
+  return MemoryUsage(initial_size,
+                     _survivor_space_used,
+                     _survivor_space_committed,
+                     max_size);
+}
+
+MemoryUsage G1MonitoringSupport::old_gen_memory_usage(size_t initial_size, size_t max_size) {
+  MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
+
+  return MemoryUsage(initial_size,
+                     _old_gen_used,
+                     _old_gen_committed,
+                     max_size);
+}
+
 G1MonitoringScope::G1MonitoringScope(G1MonitoringSupport* g1mm, bool full_gc, bool all_memory_pools_affected) :
   _tcs(full_gc ? g1mm->_full_collection_counters : g1mm->_incremental_collection_counters),
   _tms(full_gc ? &g1mm->_full_gc_memory_manager : &g1mm->_incremental_memory_manager,
--- a/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp	Tue Sep 04 12:18:35 2018 +0200
@@ -29,6 +29,7 @@
 #include "gc/shared/generationCounters.hpp"
 #include "services/memoryManager.hpp"
 #include "services/memoryService.hpp"
+#include "runtime/mutex.hpp"
 
 class CollectorCounters;
 class G1CollectedHeap;
@@ -198,6 +199,8 @@
   ~G1MonitoringSupport();
 
   void initialize_serviceability();
+
+  MemoryUsage memory_usage();
   GrowableArray<GCMemoryManager*> memory_managers();
   GrowableArray<MemoryPool*> memory_pools();
 
@@ -230,16 +233,22 @@
   //   MemoryService
   //   jstat counters
   //   Tracing
+  // Values may not be consistent wrt to each other.
 
   size_t young_gen_committed()        { return _young_gen_committed; }
 
-  size_t eden_space_committed()       { return _eden_space_committed; }
   size_t eden_space_used()            { return _eden_space_used; }
-  size_t survivor_space_committed()   { return _survivor_space_committed; }
   size_t survivor_space_used()        { return _survivor_space_used; }
 
   size_t old_gen_committed()          { return _old_gen_committed; }
   size_t old_gen_used()               { return _old_gen_used; }
+
+  // Monitoring support for MemoryPools. Values in the returned MemoryUsage are
+  // guaranteed to be consistent with each other.
+  MemoryUsage eden_space_memory_usage(size_t initial_size, size_t max_size);
+  MemoryUsage survivor_space_memory_usage(size_t initial_size, size_t max_size);
+
+  MemoryUsage old_gen_memory_usage(size_t initial_size, size_t max_size);
 };
 
 // Scope object for java.lang.management support.
--- a/src/hotspot/share/gc/shared/collectedHeap.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/shared/collectedHeap.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -328,6 +328,11 @@
   } while (true);  // Until a GC is done
 }
 
+MemoryUsage CollectedHeap::memory_usage() {
+  return MemoryUsage(InitialHeapSize, used(), capacity(), max_capacity());
+}
+
+
 #ifndef PRODUCT
 void CollectedHeap::check_for_non_bad_heap_word_value(HeapWord* addr, size_t size) {
   if (CheckMemoryInitialization && ZapUnusedHeapArea) {
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp	Tue Sep 04 12:18:35 2018 +0200
@@ -31,6 +31,7 @@
 #include "runtime/handles.hpp"
 #include "runtime/perfData.hpp"
 #include "runtime/safepoint.hpp"
+#include "services/memoryUsage.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/events.hpp"
 #include "utilities/formatBuffer.hpp"
@@ -423,6 +424,7 @@
   // Return the SoftRefPolicy for the heap;
   virtual SoftRefPolicy* soft_ref_policy() = 0;
 
+  virtual MemoryUsage memory_usage();
   virtual GrowableArray<GCMemoryManager*> memory_managers() = 0;
   virtual GrowableArray<MemoryPool*> memory_pools() = 0;
 
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -88,6 +88,7 @@
 Mutex*   Shared_DirtyCardQ_lock       = NULL;
 Mutex*   MarkStackFreeList_lock       = NULL;
 Mutex*   MarkStackChunkList_lock      = NULL;
+Mutex*   MonitoringSupport_lock       = NULL;
 Mutex*   ParGCRareEvent_lock          = NULL;
 Mutex*   DerivedPointerTableGC_lock   = NULL;
 Monitor* CGCPhaseManager_lock         = NULL;
@@ -216,6 +217,8 @@
 
     def(MarkStackFreeList_lock     , PaddedMutex  , leaf     ,   true,  Monitor::_safepoint_check_never);
     def(MarkStackChunkList_lock    , PaddedMutex  , leaf     ,   true,  Monitor::_safepoint_check_never);
+
+    def(MonitoringSupport_lock     , PaddedMutex  , native   ,   true,  Monitor::_safepoint_check_never);      // used for serviceability monitoring support
   }
   def(ParGCRareEvent_lock          , PaddedMutex  , leaf     ,   true,  Monitor::_safepoint_check_sometimes);
   def(DerivedPointerTableGC_lock   , PaddedMutex  , leaf,        true,  Monitor::_safepoint_check_never);
--- a/src/hotspot/share/runtime/mutexLocker.hpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Tue Sep 04 12:18:35 2018 +0200
@@ -94,6 +94,7 @@
                                                  // non-Java threads.
 extern Mutex*   MarkStackFreeList_lock;          // Protects access to the global mark stack free list.
 extern Mutex*   MarkStackChunkList_lock;         // Protects access to the global mark stack chunk list.
+extern Mutex*   MonitoringSupport_lock;          // Protects updates to the serviceability memory pools.
 extern Mutex*   ParGCRareEvent_lock;             // Synchronizes various (rare) parallel GC ops.
 extern Mutex*   Compile_lock;                    // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
 extern Monitor* MethodCompileQueue_lock;         // a lock held when method compilations are enqueued, dequeued
--- a/src/hotspot/share/services/management.cpp	Tue Sep 04 12:17:23 2018 +0200
+++ b/src/hotspot/share/services/management.cpp	Tue Sep 04 12:18:35 2018 +0200
@@ -713,50 +713,53 @@
 JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap))
   ResourceMark rm(THREAD);
 
-  // Calculate the memory usage
-  size_t total_init = 0;
-  size_t total_used = 0;
-  size_t total_committed = 0;
-  size_t total_max = 0;
-  bool   has_undefined_init_size = false;
-  bool   has_undefined_max_size = false;
+  MemoryUsage usage;
+
+  if (heap) {
+    usage = Universe::heap()->memory_usage();
+  } else {
+    // Calculate the memory usage by summing up the pools.
+    size_t total_init = 0;
+    size_t total_used = 0;
+    size_t total_committed = 0;
+    size_t total_max = 0;
+    bool   has_undefined_init_size = false;
+    bool   has_undefined_max_size = false;
 
-  for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
-    MemoryPool* pool = MemoryService::get_memory_pool(i);
-    if ((heap && pool->is_heap()) || (!heap && pool->is_non_heap())) {
-      MemoryUsage u = pool->get_memory_usage();
-      total_used += u.used();
-      total_committed += u.committed();
+    for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
+      MemoryPool* pool = MemoryService::get_memory_pool(i);
+      if (pool->is_non_heap()) {
+        MemoryUsage u = pool->get_memory_usage();
+        total_used += u.used();
+        total_committed += u.committed();
 
-      if (u.init_size() == (size_t)-1) {
-        has_undefined_init_size = true;
-      }
-      if (!has_undefined_init_size) {
-        total_init += u.init_size();
-      }
+        if (u.init_size() == MemoryUsage::undefined_size()) {
+          has_undefined_init_size = true;
+        }
+        if (!has_undefined_init_size) {
+          total_init += u.init_size();
+        }
 
-      if (u.max_size() == (size_t)-1) {
-        has_undefined_max_size = true;
-      }
-      if (!has_undefined_max_size) {
-        total_max += u.max_size();
+        if (u.max_size() == MemoryUsage::undefined_size()) {
+          has_undefined_max_size = true;
+        }
+        if (!has_undefined_max_size) {
+          total_max += u.max_size();
+        }
       }
     }
-  }
 
-  // if any one of the memory pool has undefined init_size or max_size,
-  // set it to -1
-  if (has_undefined_init_size) {
-    total_init = (size_t)-1;
+    // if any one of the memory pool has undefined init_size or max_size,
+    // set it to MemoryUsage::undefined_size()
+    if (has_undefined_init_size) {
+      total_init = MemoryUsage::undefined_size();
+    }
+    if (has_undefined_max_size) {
+      total_max = MemoryUsage::undefined_size();
+    }
+
+    usage = MemoryUsage(total_init, total_used, total_committed, total_max);
   }
-  if (has_undefined_max_size) {
-    total_max = (size_t)-1;
-  }
-
-  MemoryUsage usage((heap ? InitialHeapSize : total_init),
-                    total_used,
-                    total_committed,
-                    (heap ? Universe::heap()->max_capacity() : total_max));
 
   Handle obj = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
   return JNIHandles::make_local(env, obj());