< prev index next >

src/hotspot/share/memory/metaspace.cpp

Print this page
rev 50036 : imported patch 8202634-simplify-spacemanager

@@ -298,15 +298,15 @@
   // the chunk manager (the freelist if non-humongous, the dictionary if
   // humongous).
   void remove_chunk(Metachunk* chunk);
 
   // Return a single chunk of type index to the ChunkManager.
-  void return_single_chunk(ChunkIndex index, Metachunk* chunk);
+  void return_single_chunk(Metachunk* chunk);
 
   // Add the simple linked list of chunks to the freelist of chunks
   // of type index.
-  void return_chunk_list(ChunkIndex index, Metachunk* chunk);
+  void return_chunk_list(Metachunk* chunks);
 
   // Total of the space in the free chunks list
   size_t free_chunks_total_words();
   size_t free_chunks_total_bytes();
 

@@ -1283,11 +1283,11 @@
   const Metaspace::MetaspaceType  _space_type;
 
   // List of chunks in use by this SpaceManager.  Allocations
   // are done from the current chunk.  The list is used for deallocating
   // chunks when the SpaceManager is freed.
-  Metachunk* _chunks_in_use[NumberOfInUseLists];
+  Metachunk* _chunk_list;
   Metachunk* _current_chunk;
 
   // Maximum number of small chunks to allocate to a SpaceManager
   static uint const _small_chunk_limit;
 

@@ -1300,23 +1300,21 @@
   // Note: capacity = used + free + waste + overhead. We do not keep running counters for
   // free and waste. Their sum can be deduced from the three other values.
   size_t _overhead_words;
   size_t _capacity_words;
   size_t _used_words;
+  uintx _num_chunks_by_type[NumberOfInUseLists];
 
   // Free lists of blocks are per SpaceManager since they
   // are assumed to be in chunks in use by the SpaceManager
   // and all chunks in use by a SpaceManager are freed when
   // the class loader using the SpaceManager is collected.
   BlockFreelist* _block_freelists;
 
  private:
   // Accessors
-  Metachunk* chunks_in_use(ChunkIndex index) const { return _chunks_in_use[index]; }
-  void set_chunks_in_use(ChunkIndex index, Metachunk* v) {
-    _chunks_in_use[index] = v;
-  }
+  Metachunk* chunk_list() const { return _chunk_list; }
 
   BlockFreelist* block_freelists() const { return _block_freelists; }
 
   Metaspace::MetadataType mdtype() { return _mdtype; }
 

@@ -1340,13 +1338,10 @@
   void add_to_statistics_locked(SpaceManagerStatistics* out) const;
 
   // Verify internal counters against the current state. Expects to be locked with lock().
   DEBUG_ONLY(void verify_metrics_locked() const;)
 
- protected:
-  void initialize();
-
  public:
   SpaceManager(Metaspace::MetadataType mdtype,
                Metaspace::MetaspaceType space_type,
                Mutex* lock);
   ~SpaceManager();

@@ -1395,11 +1390,11 @@
 
   // Get the initial chunks size for this metaspace type.
   size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
 
   // Todo: remove this once we have counters by chunk type.
-  size_t sum_count_in_chunks_in_use(ChunkIndex i);
+  uintx num_chunks_by_type(ChunkIndex chunk_type) const       { return _num_chunks_by_type[chunk_type]; }
 
   Metachunk* get_new_chunk(size_t chunk_word_size);
 
   // Block allocation and deallocation.
   // Allocates a block from the current chunk

@@ -1621,11 +1616,11 @@
     // will assert that).
     do_update_in_use_info_for_chunk(padding_chunk, true);
 
     // Return Chunk to freelist.
     inc_container_count();
-    chunk_manager->return_single_chunk(padding_chunk_type, padding_chunk);
+    chunk_manager->return_single_chunk(padding_chunk);
     // Please note: at this point, ChunkManager::return_single_chunk()
     // may already have merged the padding chunk with neighboring chunks, so
     // it may have vanished at this point. Do not reference the padding
     // chunk beyond this point.
   }

@@ -2125,11 +2120,11 @@
       // size should be a multiple of the smallest chunk size, we
       // should always be able to fill the VirtualSpace completely.
       if (chunk == NULL) {
         break;
       }
-      chunk_manager->return_single_chunk(index, chunk);
+      chunk_manager->return_single_chunk(chunk);
     }
     DEBUG_ONLY(verify_container_count();)
   }
   assert(free_words_in_vs() == 0, "should be empty now");
 }

@@ -3045,11 +3040,12 @@
   }
 
   return chunk;
 }
 
-void ChunkManager::return_single_chunk(ChunkIndex index, Metachunk* chunk) {
+void ChunkManager::return_single_chunk(Metachunk* chunk) {
+  const ChunkIndex index = chunk->get_chunk_type();
   assert_lock_strong(MetaspaceExpand_lock);
   DEBUG_ONLY(do_verify_chunk(chunk);)
   assert(chunk->get_chunk_type() == index, "Chunk does not match expected index.");
   assert(chunk != NULL, "Expected chunk.");
   assert(chunk->container() != NULL, "Container should have been set.");

@@ -3096,18 +3092,17 @@
     }
   }
 
 }
 
-void ChunkManager::return_chunk_list(ChunkIndex index, Metachunk* chunks) {
-  index_bounds_check(index);
+void ChunkManager::return_chunk_list(Metachunk* chunks) {
   if (chunks == NULL) {
     return;
   }
   LogTarget(Trace, gc, metaspace, freelist) log;
   if (log.is_enabled()) { // tracing
-    log.print("returning list of %s chunks...", chunk_size_name(index));
+    log.print("returning list of chunks...");
   }
   unsigned num_chunks_returned = 0;
   size_t size_chunks_returned = 0;
   Metachunk* cur = chunks;
   while (cur != NULL) {

@@ -3116,21 +3111,16 @@
     Metachunk* next = cur->next();
     if (log.is_enabled()) { // tracing
       num_chunks_returned ++;
       size_chunks_returned += cur->word_size();
     }
-    return_single_chunk(index, cur);
+    return_single_chunk(cur);
     cur = next;
   }
   if (log.is_enabled()) { // tracing
-    log.print("returned %u %s chunks to freelist, total word size " SIZE_FORMAT ".",
-        num_chunks_returned, chunk_size_name(index), size_chunks_returned);
-    if (index != HumongousIndex) {
-      log.print("updated freelist count: " SIZE_FORMAT ".", free_chunks(index)->size());
-    } else {
-      log.print("updated dictionary count " SIZE_FORMAT ".", _humongous_dictionary.total_count());
-    }
+    log.print("returned %u chunks to freelist, total word size " SIZE_FORMAT ".",
+        num_chunks_returned, size_chunks_returned);
   }
 }
 
 void ChunkManager::print_on(outputStream* out) const {
   _humongous_dictionary.report_statistics(out);

@@ -3193,32 +3183,15 @@
          SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted);
 
   return adjusted;
 }
 
-size_t SpaceManager::sum_count_in_chunks_in_use(ChunkIndex i) {
-  size_t count = 0;
-  Metachunk* chunk = chunks_in_use(i);
-  while (chunk != NULL) {
-    count++;
-    chunk = chunk->next();
-  }
-  return count;
-}
-
 void SpaceManager::locked_print_chunks_in_use_on(outputStream* st) const {
 
   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
-    Metachunk* chunk = chunks_in_use(i);
-    st->print("SpaceManager: %s " PTR_FORMAT,
-                 chunk_size_name(i), p2i(chunk));
-    if (chunk != NULL) {
-      st->print_cr(" free " SIZE_FORMAT,
-                   chunk->free_word_size());
-    } else {
-      st->cr();
-    }
+    st->print("SpaceManager: " UINTX_FORMAT " %s chunks.",
+        num_chunks_by_type(i), chunk_size_name(i));
   }
 
   chunk_manager()->locked_print_free_chunks(st);
   chunk_manager()->locked_print_sum_free_chunks(st);
 }

@@ -3236,17 +3209,17 @@
   // Instead of jumping to SmallChunk after initial chunk exhausted, keeping allocation
   // from SpecializeChunk up to _anon_or_delegating_metadata_specialize_chunk_limit (4)
   // reduces space waste from 60+% to around 30%.
   if ((_space_type == Metaspace::AnonymousMetaspaceType || _space_type == Metaspace::ReflectionMetaspaceType) &&
       _mdtype == Metaspace::NonClassType &&
-      sum_count_in_chunks_in_use(SpecializedIndex) < _anon_and_delegating_metadata_specialize_chunk_limit &&
+      num_chunks_by_type(SpecializedIndex) < _anon_and_delegating_metadata_specialize_chunk_limit &&
       word_size + Metachunk::overhead() <= SpecializedChunk) {
     return SpecializedChunk;
   }
 
-  if (chunks_in_use(MediumIndex) == NULL &&
-      sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit) {
+  if (num_chunks_by_type(MediumIndex) == 0 &&
+      num_chunks_by_type(SmallIndex) < _small_chunk_limit) {
     chunk_word_size = (size_t) small_chunk_size();
     if (word_size + Metachunk::overhead() > small_chunk_size()) {
       chunk_word_size = medium_chunk_size();
     }
   } else {

@@ -3348,21 +3321,27 @@
   _space_type(space_type),
   _capacity_words(0),
   _used_words(0),
   _overhead_words(0),
   _block_freelists(NULL),
-  _lock(lock)
+  _lock(lock),
+  _chunk_list(NULL),
+  _current_chunk(NULL)
 {
-  initialize();
+  Metadebug::init_allocation_fail_alot_count();
+  memset(_num_chunks_by_type, 0, sizeof(_num_chunks_by_type));
+  log_trace(gc, metaspace, freelist)("SpaceManager(): " PTR_FORMAT, p2i(this));
 }
 
 void SpaceManager::account_for_new_chunk(const Metachunk* new_chunk) {
 
   assert_lock_strong(MetaspaceExpand_lock);
 
   _capacity_words += new_chunk->word_size();
   _overhead_words += Metachunk::overhead();
+  DEBUG_ONLY(new_chunk->verify());
+  _num_chunks_by_type[new_chunk->get_chunk_type()] ++;
 
   // Adjust global counters:
   MetaspaceUtils::inc_capacity(mdtype(), new_chunk->word_size());
   MetaspaceUtils::inc_overhead(mdtype(), Metachunk::overhead());
 }

@@ -3386,19 +3365,10 @@
   MetaspaceUtils::dec_capacity(mdtype(), _capacity_words);
   MetaspaceUtils::dec_overhead(mdtype(), _overhead_words);
   MetaspaceUtils::dec_used(mdtype(), _used_words);
 }
 
-void SpaceManager::initialize() {
-  Metadebug::init_allocation_fail_alot_count();
-  for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
-    _chunks_in_use[i] = NULL;
-  }
-  _current_chunk = NULL;
-  log_trace(gc, metaspace, freelist)("SpaceManager(): " PTR_FORMAT, p2i(this));
-}
-
 SpaceManager::~SpaceManager() {
 
   // This call this->_lock which can't be done while holding MetaspaceExpand_lock
   DEBUG_ONLY(verify_metrics());
 

@@ -3424,16 +3394,15 @@
   // Add all the chunks in use by this space manager
   // to the global list of free chunks.
 
   // Follow each list of chunks-in-use and add them to the
   // free lists.  Each list is NULL terminated.
-
-  for (ChunkIndex i = ZeroIndex; i <= HumongousIndex; i = next_chunk_index(i)) {
-    Metachunk* chunks = chunks_in_use(i);
-    chunk_manager()->return_chunk_list(i, chunks);
-    set_chunks_in_use(i, NULL);
-  }
+  chunk_manager()->return_chunk_list(chunk_list());
+#ifdef ASSERT
+  _chunk_list = NULL;
+  _current_chunk = NULL;
+#endif
 
   chunk_manager()->slow_locked_verify();
 
   if (_block_freelists != NULL) {
     delete _block_freelists;

@@ -3471,12 +3440,12 @@
     retire_current_chunk();
     set_current_chunk(new_chunk);
   }
 
   // Add the new chunk at the head of its respective chunk list.
-  new_chunk->set_next(chunks_in_use(index));
-  set_chunks_in_use(index, new_chunk);
+  new_chunk->set_next(_chunk_list);
+  _chunk_list = new_chunk;
 
   // Adjust counters.
   account_for_new_chunk(new_chunk);
 
   assert(new_chunk->is_empty(), "Not ready for reuse");

@@ -3566,26 +3535,22 @@
     result = grow_and_allocate(word_size);
   }
 
   if (result != NULL) {
     account_for_allocation(word_size);
-    assert(result != (MetaWord*) chunks_in_use(MediumIndex),
-           "Head of the list is being allocated");
   }
 
   return result;
 }
 
 void SpaceManager::verify() {
-  for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
-    Metachunk* curr = chunks_in_use(i);
+  Metachunk* curr = chunk_list();
     while (curr != NULL) {
       DEBUG_ONLY(do_verify_chunk(curr);)
       assert(curr->is_tagged_free() == false, "Chunk should be tagged as in use.");
       curr = curr->next();
     }
-  }
 }
 
 void SpaceManager::verify_chunk_size(Metachunk* chunk) {
   assert(is_humongous(chunk->word_size()) ||
          chunk->word_size() == medium_chunk_size() ||

@@ -3595,14 +3560,13 @@
   return;
 }
 
 void SpaceManager::add_to_statistics_locked(SpaceManagerStatistics* out) const {
   assert_lock_strong(lock());
-  for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
-    UsedChunksStatistics& chunk_stat = out->chunk_stats(i);
-    Metachunk* chunk = chunks_in_use(i);
+  Metachunk* chunk = chunk_list();
     while (chunk != NULL) {
+    UsedChunksStatistics& chunk_stat = out->chunk_stats(chunk->get_chunk_type());
       chunk_stat.add_num(1);
       chunk_stat.add_cap(chunk->word_size());
       chunk_stat.add_overhead(Metachunk::overhead());
       chunk_stat.add_used(chunk->used_word_size() - Metachunk::overhead());
       if (chunk != current_chunk()) {

@@ -3610,11 +3574,10 @@
       } else {
         chunk_stat.add_free(chunk->free_word_size());
       }
       chunk = chunk->next();
     }
-  }
   if (block_freelists() != NULL) {
     out->add_free_blocks_info(block_freelists()->num_blocks(), block_freelists()->total_size());
   }
 }
 
< prev index next >