rev 57601 : [mq]: metaspace-improvement

   1 /*
   2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 #include "precompiled.hpp"
  25 
  26 
  27 #include "logging/log.hpp"
  28 #include "memory/metaspace/constants.hpp"
  29 #include "memory/metaspace/chunkAllocSequence.hpp"
  30 #include "memory/metaspace/chunkLevel.hpp"
  31 #include "memory/metaspace/chunkManager.hpp"
  32 #include "memory/metaspace/metachunk.hpp"


  33 #include "memory/metaspace/metaspaceStatistics.hpp"

  34 #include "memory/metaspace/virtualSpaceNode.hpp"
  35 #include "memory/metaspace/virtualSpaceList.hpp"
  36 #include "runtime/mutexLocker.hpp"
  37 #include "utilities/debug.hpp"
  38 #include "utilities/globalDefinitions.hpp"

  39 
  40 namespace metaspace {
  41 
  42 
  43 // Return a single chunk to the freelist and adjust accounting. No merge is attempted.
  44 void ChunkManager::return_chunk_simple(Metachunk* c) {
  45   DEBUG_ONLY(c->verify(false));
  46   const chklvl_t lvl = c->level();
  47   _chunks[lvl].add(c);
  48   _total_word_size.increment_by(c->word_size());
  49   _committed_word_size.increment_by(c->committed_words());
  50 }
  51 
  52 // Take a single chunk from the given freelist and adjust counters. Returns NULL
  53 // if there is no fitting chunk for this level.
  54 Metachunk* ChunkManager::remove_first_chunk_at_level(chklvl_t l) {
  55   DEBUG_ONLY(chklvl::check_valid_level(l);)
  56   Metachunk* c = _chunks[l].remove_first();
  57   if (c != NULL) {
  58     _total_word_size.decrement_by(c->word_size());
  59     _committed_word_size.decrement_by(c->committed_words());
  60   }
  61   return c;
  62 }
  63 
  64 // Creates a chunk manager with a given name (which is for debug purposes only)
  65 // and an associated space list which will be used to request new chunks from
  66 // (see get_chunk())
  67 ChunkManager::ChunkManager(const char* name, VirtualSpaceList* space_list)
  68   : _vslist(space_list),
  69     _name(name),
  70     _chunks()
  71 {
  72 }
  73 
  74 // Given a chunk we are about to handout to the caller, make sure it is committed
  75 // according to constants::committed_words_on_fresh_chunks
  76 bool ChunkManager::commit_chunk_before_handout(Metachunk* c) {
  77   const size_t must_be_committed = MIN2(c->word_size(), constants::committed_words_on_fresh_chunks);
  78   return c->ensure_committed(must_be_committed);
  79 }
  80 
  81 #ifdef ASSERT
  82 // Given a splinters array returned from a split operation, check that it meets expectations
  83 static void check_splinters_array(Metachunk* splinters[chklvl::NUM_CHUNK_LEVELS], chklvl_t min, chklvl_t max) {
  84   // The array shall contain splinters in the range [min, max] and nothing outside. The chunk levels for
  85   // the chunks must match too.
  86   for (chklvl_t l = chklvl::ROOT_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
  87     if (l >= min && l < max) {
  88       assert(splinters[l] != NULL, "Missing splinters");
  89       assert(splinters[l]->level() == l, "Unexpected level");
  90       splinters[l]->verify(false);
  91     } else {
  92       assert(splinters[l] == NULL, "Unexpected splinters");
  93     }
  94   }



  95 }































































































  96 #endif
  97 


  98 
  99 // Given a chunk which must be outside of a freelist and must be free, split it to
 100 // meet a target level and return it. Splinters are added to the freelist.
 101 Metachunk* ChunkManager::split_chunk_and_add_splinters(Metachunk* c, chklvl_t target_level) {
 102 
 103   assert(c->is_free() && c->level() > target_level, "Invalid chunk for splitting");
 104   DEBUG_ONLY(chklvl::check_valid_level(target_level);)
 105 
 106   const chklvl_t orig_level = c->level();
 107   Metachunk* splinters[chklvl::NUM_CHUNK_LEVELS] = { 0 };
 108   c = c->vsnode()->split(target_level, c, splinters);
 109 
 110   // Splitting should never fail.
 111   assert(c != NULL, "Split failed");
 112   assert(c->level() == target_level, "Sanity");
 113   DEBUG_ONLY(c->verify(false));
 114   DEBUG_ONLY(check_splinters_array(splinters, orig_level + 1, target_level);)
 115 
 116   // Return splinters to freelist.
 117   for (chklvl_t l = orig_level + 1; l <= target_level; l ++) {
 118     return_chunk_simple(splinters[l]);
 119   }
 120 
 121   return c;
 122 }
 123 
 124 // Get a chunk and be smart about it.
 125 // - 1) Attempt to find a free chunk of exactly the pref_level level
 126 // - 2) Failing that, attempt to find a chunk smaller or equal the minimal level.
 127 // - 3) Failing that, attempt to find a free chunk of larger size and split it.
 128 // - 4) Failing that, attempt to allocate a new chunk from the connected virtual space.
 129 // - Failing that, give up and return NULL.
 130 // Note: this is not guaranteed to return a *committed* chunk. The chunk manager will
 131 //   attempt to commit the returned chunk according to constants::committed_words_on_fresh_chunks;
 132 //   but this may fail if we hit a commit limit. In that case, a partly uncommit chunk
 133 //   will be returned, and the commit is attempted again when we allocate from the chunk's
 134 //   uncommitted area. See also Metachunk::allocate.
 135 Metachunk* ChunkManager::get_chunk(chklvl_t min_level, chklvl_t pref_level) {
 136 


 137   assert_lock_strong(MetaspaceExpand_lock);
 138   DEBUG_ONLY(chklvl::check_valid_level(min_level);)
 139   DEBUG_ONLY(chklvl::check_valid_level(pref_level);)

 140 
 141   Metachunk* c = NULL;




















 142 
 143   // 1) Attempt to find a free chunk of exactly the pref_level level
 144   c = remove_first_chunk_at_level(pref_level);




 145 
 146   // 2) Failing that, attempt to find a chunk smaller or equal the minimal level.
 147   if (c == NULL) {
 148     for (chklvl_t lvl = pref_level + 1; lvl <= min_level; lvl ++) {
 149       c = remove_first_chunk_at_level(lvl);
 150       if (c != NULL) {
 151         break;














 152       }
 153     }
 154   }
 155 
 156   // 3) Failing that, attempt to find a free chunk of larger size and split it.
 157   if (c == NULL) {
 158     for (chklvl_t lvl = pref_level - 1; lvl >= chklvl::ROOT_CHUNK_LEVEL; lvl --) {
 159       c = remove_first_chunk_at_level(lvl);
 160       if (c != NULL) {
 161         // Split chunk; add splinters to freelist
 162         c = split_chunk_and_add_splinters(c, pref_level);


















































































 163         break;



 164       }
 165     }


























 166   }
 167 
 168   // 4) Failing that, attempt to allocate a new chunk from the connected virtual space.
 169   if (c == NULL) {









 170 
 171     c = _vslist->allocate_root_chunk();

 172 
 173     // This should always work. Note that getting the root chunk may not mean we committed memory.
 174     assert(c != NULL, "Unexpected");
 175 
 176     // Split this root chunk to the desired chunk size.
 177     c = split_chunk_and_add_splinters(c, pref_level);
 178 
 179   }




 180 
 181   // Note that we should at this point have a chunk; should always work. If we hit
 182   // a commit limit in the meantime, the chunk may still be uncommitted, but the chunk
 183   // itself should exist now.
 184   assert(c != NULL, "Unexpected");
 185 
 186   // Before returning the chunk, attempt to commit it according to the handout rules.
 187   // If that fails, we ignore the error and return the uncommitted chunk.
 188   if (commit_chunk_before_handout(c) == false) {
 189     log_info(gc, metaspace)("Failed to commit chunk prior to handout.");




 190   }
 191 
 192   DEBUG_ONLY(verify(false);)


 193 
 194   return c;







 195 
 196 } // ChunkManager::get_chunk



 197 

 198 
 199 // Return a single chunk to the ChunkManager and adjust accounting. May merge chunk
 200 //  with neighbors.
 201 // Happens after a Classloader was unloaded and releases its metaspace chunks.
 202 // !! Note: this may invalidate the chunk. Do not access the chunk after
 203 //    this function returns !!
 204 void ChunkManager::return_chunk(Metachunk* c) {
 205 
 206   assert_lock_strong(MetaspaceExpand_lock);
 207   DEBUG_ONLY(c->verify(false);)
 208 
 209   const chklvl_t orig_lvl = c->level();

 210 
 211   int num_merged[chklvl::NUM_CHUNK_LEVELS] = { 0 };
 212   Metachunk* c2 = c->vsnode()->merge(c, num_merged);

 213 
 214   if (c2 != NULL) {
 215     DEBUG_ONLY(c2->verify(false));
 216 
 217     // We did merge chunks and now have a bigger chunk.
 218     assert(c2->level() < orig_lvl, "Sanity");
 219 
 220     // Adjust counters - the merged-in chunks have been removed from the free lists, but the counters
 221     // in this chunk manager must be adjusted too.
 222     size_t size_chunks_removed = 0;
 223     for (chklvl_t l = chklvl::ROOT_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
 224       if (num_merged[l] > 0) {
 225         // Since we have a binary tree, we should exactly see one merge per level.
 226         assert(num_merged[l] == 1, "sanity");
 227         _chunks[l].dec_counter_by(1);
 228         size_chunks_removed += chklvl::word_size_for_level(l);
 229       }



 230     }
 231     _total_word_size.decrement_by(size_chunks_removed);
 232 
 233     c = c2;
 234   }



 235 
 236   return_chunk_simple(c);


 237 
 238 }

 239 









 240 
 241 ChunkManager* ChunkManager::_chunkmanager_class = NULL;
 242 ChunkManager* ChunkManager::_chunkmanager_nonclass = NULL;
 243 
 244 void ChunkManager::set_chunkmanager_class(ChunkManager* cm) {
 245   assert(_chunkmanager_class == NULL, "Sanity");
 246   _chunkmanager_class = cm;
 247 }
 248 
 249 void ChunkManager::set_chunkmanager_nonclass(ChunkManager* cm) {
 250   assert(_chunkmanager_nonclass == NULL, "Sanity");
 251   _chunkmanager_nonclass = cm;
 252 }
 253 


 254 
 255 // Update statistics.
 256 void ChunkManager::add_to_statistics(ChunkManagerStatistics* out) const {



 257 
 258   for (chklvl_t l = chklvl::ROOT_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
 259     out->num_chunks[l] += _chunks[l].size();















 260   }
 261 

 262 }
 263 


 264 #ifdef ASSERT








































 265 
 266 void ChunkManager::verify(bool slow) const {

 267 
 268   size_t word_size = 0;
 269   size_t committed_word_size = 0;
 270   for (chklvl_t l = chklvl::LOWEST_CHUNK_LEVEL;
 271        l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++)
 272   {
 273     const Metachunk* c = _chunks[l].first();
 274     int num = 0;
 275     while (c) {
 276       assert(c->level() == l, "Wrong level");
 277       assert(c->is_free(), "Chunk is not free.");
 278       num ++;
 279       committed_word_size += c->committed_words();
 280       c->verify(slow);
 281       c = c->next();
 282     }
 283     assert(num == _chunks[l].size(), "Sanity");
 284     word_size += num * chklvl::word_size_for_level(l);
 285   }
 286   _total_word_size.check(word_size);
 287   _committed_word_size.check(committed_word_size);









 288 
 289 }
 290 
 291 #endif // ASSERT


























 292 






 293 
 294 } // namespace metaspace
 295 
 296 
 297 
--- EOF ---