< prev index next >

src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp

Print this page
rev 53911 : 8218988: Improve metaspace verifications
Reviewed-by:

@@ -27,10 +27,11 @@
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/metaspace/metachunk.hpp"
 #include "memory/metaspace.hpp"
 #include "memory/metaspace/chunkManager.hpp"
+#include "memory/metaspace/metaDebug.hpp"
 #include "memory/metaspace/metaspaceCommon.hpp"
 #include "memory/metaspace/occupancyMap.hpp"
 #include "memory/metaspace/virtualSpaceNode.hpp"
 #include "memory/virtualspace.hpp"
 #include "runtime/os.hpp"

@@ -71,11 +72,12 @@
     MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass);
   }
 }
 
 void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
-  DEBUG_ONLY(this->verify();)
+  // When a node is purged, lets give it a thorough examination.
+  DEBUG_ONLY(verify(true);)
     Metachunk* chunk = first_chunk();
   Metachunk* invalid_chunk = (Metachunk*) top();
   while (chunk < invalid_chunk ) {
     assert(chunk->is_tagged_free(), "Should be tagged free");
     MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();

@@ -169,80 +171,78 @@
   }
 }
 
 
 #ifdef ASSERT
-uintx VirtualSpaceNode::container_count_slow() {
-  uintx count = 0;
-  Metachunk* chunk = first_chunk();
-  Metachunk* invalid_chunk = (Metachunk*) top();
-  while (chunk < invalid_chunk ) {
-    MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
-    do_verify_chunk(chunk);
-    // Don't count the chunks on the free lists.  Those are
-    // still part of the VirtualSpaceNode but not currently
-    // counted.
-    if (!chunk->is_tagged_free()) {
-      count++;
-    }
-    chunk = (Metachunk*) next;
-  }
-  return count;
-}
-#endif
 
-#ifdef ASSERT
 // Verify counters, all chunks in this list node and the occupancy map.
-void VirtualSpaceNode::verify() {
+void VirtualSpaceNode::verify(bool slow) {
+  log_trace(gc, metaspace, freelist)("verifying %s virtual space node (%s).",
+    (is_class() ? "class space" : "metaspace"), (slow ? "slow" : "quick"));
+  // Fast mode: just verify chunk counters and basic geometry
+  // Slow mode: verify chunks and occupancy map
   uintx num_in_use_chunks = 0;
   Metachunk* chunk = first_chunk();
   Metachunk* invalid_chunk = (Metachunk*) top();
 
   // Iterate the chunks in this node and verify each chunk.
   while (chunk < invalid_chunk ) {
-    DEBUG_ONLY(do_verify_chunk(chunk);)
+    if (slow) {
+      do_verify_chunk(chunk);
+    }
       if (!chunk->is_tagged_free()) {
         num_in_use_chunks ++;
       }
-    MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+    const size_t s = chunk->word_size();
+    // Prevent endless loop on invalid chunk size.
+    assert(is_valid_chunksize(is_class(), s), "Invalid chunk size: " SIZE_FORMAT ".", s);
+    MetaWord* next = ((MetaWord*)chunk) + s;
     chunk = (Metachunk*) next;
   }
   assert(_container_count == num_in_use_chunks, "Container count mismatch (real: " UINTX_FORMAT
       ", counter: " UINTX_FORMAT ".", num_in_use_chunks, _container_count);
   // Also verify the occupancy map.
-  occupancy_map()->verify(this->bottom(), this->top());
+  if (slow) {
+    occupancy_map()->verify(bottom(), top());
+  }
 }
-#endif // ASSERT
 
-#ifdef ASSERT
 // Verify that all free chunks in this node are ideally merged
 // (there not should be multiple small chunks where a large chunk could exist.)
 void VirtualSpaceNode::verify_free_chunks_are_ideally_merged() {
   Metachunk* chunk = first_chunk();
   Metachunk* invalid_chunk = (Metachunk*) top();
   // Shorthands.
   const size_t size_med = (is_class() ? ClassMediumChunk : MediumChunk) * BytesPerWord;
   const size_t size_small = (is_class() ? ClassSmallChunk : SmallChunk) * BytesPerWord;
   int num_free_chunks_since_last_med_boundary = -1;
   int num_free_chunks_since_last_small_boundary = -1;
-  while (chunk < invalid_chunk ) {
+  bool error = false;
+  char err[256];
+  while (!error && chunk < invalid_chunk ) {
     // Test for missed chunk merge opportunities: count number of free chunks since last chunk boundary.
     // Reset the counter when encountering a non-free chunk.
     if (chunk->get_chunk_type() != HumongousIndex) {
       if (chunk->is_tagged_free()) {
         // Count successive free, non-humongous chunks.
         if (is_aligned(chunk, size_small)) {
-          assert(num_free_chunks_since_last_small_boundary <= 1,
-              "Missed chunk merge opportunity at " PTR_FORMAT " for chunk size " SIZE_FORMAT_HEX ".", p2i(chunk) - size_small, size_small);
+          if (num_free_chunks_since_last_small_boundary > 0) {
+            error = true;
+            jio_snprintf(err, sizeof(err), "Missed chunk merge opportunity to merge a small chunk preceding " PTR_FORMAT ".", p2i(chunk));
+          } else {
           num_free_chunks_since_last_small_boundary = 0;
+          }
         } else if (num_free_chunks_since_last_small_boundary != -1) {
           num_free_chunks_since_last_small_boundary ++;
         }
         if (is_aligned(chunk, size_med)) {
-          assert(num_free_chunks_since_last_med_boundary <= 1,
-              "Missed chunk merge opportunity at " PTR_FORMAT " for chunk size " SIZE_FORMAT_HEX ".", p2i(chunk) - size_med, size_med);
+          if (num_free_chunks_since_last_med_boundary > 0) {
+            error = true;
+            jio_snprintf(err, sizeof(err), "Missed chunk merge opportunity to merge a medium chunk preceding " PTR_FORMAT ".", p2i(chunk));
+          } else {
           num_free_chunks_since_last_med_boundary = 0;
+          }
         } else if (num_free_chunks_since_last_med_boundary != -1) {
           num_free_chunks_since_last_med_boundary ++;
         }
       } else {
         // Encountering a non-free chunk, reset counters.

@@ -253,10 +253,15 @@
       // One cannot merge areas with a humongous chunk in the middle. Reset counters.
       num_free_chunks_since_last_med_boundary = -1;
       num_free_chunks_since_last_small_boundary = -1;
     }
 
+    if (error) {
+      print_map(tty, is_class());
+      assert(false, "%s", err);
+    }
+
     MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
     chunk = (Metachunk*) next;
   }
 }
 #endif // ASSERT

@@ -269,18 +274,10 @@
 void VirtualSpaceNode::dec_container_count() {
   assert_lock_strong(MetaspaceExpand_lock);
   _container_count--;
 }
 
-#ifdef ASSERT
-void VirtualSpaceNode::verify_container_count() {
-  assert(_container_count == container_count_slow(),
-      "Inconsistency in container_count _container_count " UINTX_FORMAT
-      " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow());
-}
-#endif
-
 VirtualSpaceNode::~VirtualSpaceNode() {
   _rs.release();
   if (_occupancy_map != NULL) {
     delete _occupancy_map;
   }

@@ -307,11 +304,11 @@
 void VirtualSpaceNode::allocate_padding_chunks_until_top_is_at(MetaWord* target_top) {
 
   assert(target_top > top(), "Sanity");
 
   // Padding chunks are added to the freelist.
-  ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(this->is_class());
+  ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(is_class());
 
   // shorthands
   const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
   const size_t small_word_size = chunk_manager->small_chunk_word_size();
   const size_t med_word_size = chunk_manager->medium_chunk_word_size();

@@ -376,11 +373,11 @@
   // size.
   // Because of this alignment, me may need to create a number of padding
   // chunks. These chunks are created and added to the freelist.
 
   // The chunk manager to which we will give our padding chunks.
-  ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(this->is_class());
+  ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(is_class());
 
   // shorthands
   const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
   const size_t small_word_size = chunk_manager->small_chunk_word_size();
   const size_t med_word_size = chunk_manager->medium_chunk_word_size();

@@ -448,16 +445,17 @@
   occupancy_map()->set_chunk_starts_at_address((MetaWord*)result, true);
   do_update_in_use_info_for_chunk(result, true);
 
   inc_container_count();
 
-  if (VerifyMetaspace) {
-    DEBUG_ONLY(chunk_manager->locked_verify());
-    DEBUG_ONLY(this->verify());
-  }
-
-  DEBUG_ONLY(do_verify_chunk(result));
+#ifdef ASSERT
+  EVERY_NTH(VerifyMetaspaceInterval)
+    chunk_manager->locked_verify(true);
+    verify(true);
+  END_EVERY_NTH
+  do_verify_chunk(result);
+#endif
 
   result->inc_use_count();
 
   return result;
 }

@@ -556,12 +554,17 @@
   Copy::fill_to_words((HeapWord*) low(), word_size, 0xf1f1f1f1);
 }
 #endif // ASSERT
 
 void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
-  DEBUG_ONLY(verify_container_count();)
-  assert(this->is_class() == chunk_manager->is_class(), "Wrong ChunkManager?");
+  assert(is_class() == chunk_manager->is_class(), "Wrong ChunkManager?");
+#ifdef ASSERT
+  verify(false);
+  EVERY_NTH(VerifyMetaspaceInterval)
+    verify(true);
+  END_EVERY_NTH
+#endif
   for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) {
     ChunkIndex index = (ChunkIndex)i;
     size_t chunk_size = chunk_manager->size_by_index(index);
 
     while (free_words_in_vs() >= chunk_size) {

@@ -575,11 +578,10 @@
       if (chunk == NULL) {
         break;
       }
       chunk_manager->return_single_chunk(chunk);
     }
-    DEBUG_ONLY(verify_container_count();)
   }
   assert(free_words_in_vs() == 0, "should be empty now");
 }
 
 } // namespace metaspace
< prev index next >