8185033: On Metaspace OOM, ChunkManager composition should be logged.
authorstuefe
Sat, 22 Jul 2017 10:03:15 +0200
changeset 46709 adaac4b80549
parent 46708 33911d988626
child 46710 941f16147746
child 46711 0ccef2260315
8185033: On Metaspace OOM, ChunkManager composition should be logged. Reviewed-by: mgerdin, coleenp
hotspot/src/share/vm/memory/metaspace.cpp
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Mon Jul 24 17:26:41 2017 +0000
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Sat Jul 22 10:03:15 2017 +0200
@@ -164,6 +164,18 @@
   }
   void verify_free_chunks_count();
 
+  struct ChunkManagerStatistics {
+    size_t num_by_type[NumberOfFreeLists];
+    size_t single_size_by_type[NumberOfFreeLists];
+    size_t total_size_by_type[NumberOfFreeLists];
+    size_t num_humongous_chunks;
+    size_t total_size_humongous_chunks;
+  };
+
+  void locked_get_statistics(ChunkManagerStatistics* stat) const;
+  void get_statistics(ChunkManagerStatistics* stat) const;
+  static void print_statistics(const ChunkManagerStatistics* stat, outputStream* out);
+
  public:
 
   ChunkManager(size_t specialized_size, size_t small_size, size_t medium_size)
@@ -181,7 +193,7 @@
   ChunkIndex list_index(size_t size);
 
   // Map a given index to the chunk size.
-  size_t size_by_index(ChunkIndex index);
+  size_t size_by_index(ChunkIndex index) const;
 
   // Take a chunk from the ChunkManager. The chunk is expected to be in
   // the chunk manager (the freelist if non-humongous, the dictionary if
@@ -266,6 +278,10 @@
   void locked_print_sum_free_chunks(outputStream* st);
 
   void print_on(outputStream* st) const;
+
+  // Prints composition for both non-class and (if available)
+  // class chunk manager.
+  static void print_all_chunkmanagers(outputStream* out);
 };
 
 class SmallBlocks : public CHeapObj<mtClass> {
@@ -1789,10 +1805,10 @@
   return HumongousIndex;
 }
 
-size_t ChunkManager::size_by_index(ChunkIndex index) {
+size_t ChunkManager::size_by_index(ChunkIndex index) const {
   index_bounds_check(index);
   assert(index != HumongousIndex, "Do not call for humongous chunks.");
-  return free_chunks(index)->size();
+  return _free_chunks[index].size();
 }
 
 void ChunkManager::locked_verify_free_chunks_total() {
@@ -2045,7 +2061,61 @@
 }
 
 void ChunkManager::print_on(outputStream* out) const {
-  const_cast<ChunkManager *>(this)->humongous_dictionary()->report_statistics(out);
+  _humongous_dictionary.report_statistics(out);
+}
+
+void ChunkManager::locked_get_statistics(ChunkManagerStatistics* stat) const {
+  assert_lock_strong(SpaceManager::expand_lock());
+  for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
+    stat->num_by_type[i] = num_free_chunks(i);
+    stat->single_size_by_type[i] = size_by_index(i);
+    stat->total_size_by_type[i] = size_free_chunks_in_bytes(i);
+  }
+  stat->num_humongous_chunks = num_free_chunks(HumongousIndex);
+  stat->total_size_humongous_chunks = size_free_chunks_in_bytes(HumongousIndex);
+}
+
+void ChunkManager::get_statistics(ChunkManagerStatistics* stat) const {
+  MutexLockerEx cl(SpaceManager::expand_lock(),
+                   Mutex::_no_safepoint_check_flag);
+  locked_get_statistics(stat);
+}
+
+void ChunkManager::print_statistics(const ChunkManagerStatistics* stat, outputStream* out) {
+  size_t total = 0;
+  for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
+    out->print_cr("  " SIZE_FORMAT " %s (" SIZE_FORMAT " bytes) chunks, total " SIZE_FORMAT " bytes",
+                 stat->num_by_type[i], chunk_size_name(i),
+                 stat->single_size_by_type[i],
+                 stat->total_size_by_type[i]);
+    total += stat->total_size_by_type[i];
+  }
+  out->print_cr("  " SIZE_FORMAT " humongous chunks, total " SIZE_FORMAT " bytes",
+               stat->num_humongous_chunks, stat->total_size_humongous_chunks);
+  total += stat->total_size_humongous_chunks;
+  out->print_cr("  total size: " SIZE_FORMAT ".", total);
+}
+
+void ChunkManager::print_all_chunkmanagers(outputStream* out) {
+  // Note: keep lock protection only to retrieving statistics; keep printing
+  // out of lock protection
+  ChunkManagerStatistics stat;
+  out->print_cr("Chunkmanager (non-class):");
+  const ChunkManager* const non_class_cm = Metaspace::chunk_manager_metadata();
+  if (non_class_cm != NULL) {
+    non_class_cm->get_statistics(&stat);
+    ChunkManager::print_statistics(&stat, out);
+  } else {
+    out->print_cr("unavailable.");
+  }
+  out->print_cr("Chunkmanager (class):");
+  const ChunkManager* const class_cm = Metaspace::chunk_manager_class();
+  if (class_cm != NULL) {
+    class_cm->get_statistics(&stat);
+    ChunkManager::print_statistics(&stat, out);
+  } else {
+    out->print_cr("unavailable.");
+  }
 }
 
 // SpaceManager methods
@@ -3670,6 +3740,7 @@
       loader_data->dump(&ls);
     }
     MetaspaceAux::dump(&ls);
+    ChunkManager::print_all_chunkmanagers(&ls);
   }
 
   bool out_of_compressed_class_space = false;