rev 57380 : [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/virtualSpaceNode.hpp"
  34 #include "memory/metaspace/virtualSpaceList.hpp"
  35 #include "runtime/mutexLocker.hpp"
  36 #include "utilities/debug.hpp"
  37 #include "utilities/globalDefinitions.hpp"

  38 
  39 namespace metaspace {
  40 






  41 
  42 // Return a single chunk to the freelist and adjust accounting. No merge is attempted.
  43 void ChunkManager::return_chunk_simple(Metachunk* c) {
  44   DEBUG_ONLY(c->verify(false));
  45   const chklvl_t lvl = c->level();
  46   _chunks[lvl].add(c);
  47   _total_word_size.increment_by(c->word_size());
  48 }
  49 
  50 // Remove the given chunk from its free list and adjust accounting.
  51 void ChunkManager::remove_chunk(Metachunk* c) {
  52   DEBUG_ONLY(c->verify(false));
  53   const chklvl_t lvl = c->level();
  54   _chunks[lvl].remove(c);
  55   _total_word_size.decrement_by(c->word_size());
  56 }
  57 
  58 // Creates a chunk manager with a given name (which is for debug purposes only)
  59 // and an associated space list which will be used to request new chunks from
  60 // (see get_chunk())
  61 ChunkManager::ChunkManager(const char* name, VirtualSpaceList* space_list)
  62   : _vslist(space_list),
  63     _name(name)
  64 {
  65   for (int i = 0; i < chklvl::NUM_CHUNK_LEVELS; i ++) {
  66     _chunks[i] = NULL;
  67   }

































































































































































  68 }
  69 
  70 // Given a chunk we are about to handout to the caller, make sure it is committed
  71 // according to constants::committed_words_on_fresh_chunks
  72 bool ChunkManager::commit_chunk_before_handout(Metachunk* c) {
  73   const size_t must_be_committed = MIN2(c->word_size(), constants::committed_words_on_fresh_chunks);
  74   return c->ensure_committed(must_be_committed);
  75 }
  76 
  77 #ifdef ASSERT
  78 // Given a splinters array returned from a split operation, check that it meets expectations
  79 static void check_splinters_array(Metachunk* splinters[chklvl::NUM_CHUNK_LEVELS], chklvl_t min, chklvl_t max) {
  80   // The array shall contain splinters in the range [min, max] and nothing outside. The chunk levels for
  81   // the chunks must match too.
  82   for (chklvl_t l = chklvl::ROOT_CHUNK_LEVEL; l <= chklvl::HIGHEST_CHUNK_LEVEL; l ++) {
  83     if (l >= min && l < max) {
  84       assert(splinters[l] != NULL, "Missing splinters");
  85       assert(splinters[l]->level() == l, "Unexpected level");
  86       splinters[l]->verify(false);
  87     } else {
  88       assert(splinters[l] == NULL, "Unexpected splinters");
















  89     }
  90   }























  91 }
  92 #endif
  93 





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



 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       Metachunk* c = _chunks[lvl];
 160       if (c != NULL) {












 161 
 162         // Remove chunk before splitting.
 163         remove_chunk(c);
 164 
 165         // Split chunk; add splinters to freelist
 166         c = split_chunk_and_add_splinters(c, pref_level);




 167 
 168         break;
 169       }
 170     }



 171   }
 172 
 173   // 4) Failing that, attempt to allocate a new chunk from the connected virtual space.
 174   if (c == NULL) {
 175 
 176     c = _vslist->allocate_root_chunk();

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

 183 


 184   }
 185 
 186   // Note that we should at this point have a chunk; should always work. If we hit
 187   // a commit limit in the meantime, the chunk may still be uncommitted, but the chunk
 188   // itself should exist now.
 189   assert(c != NULL, "Unexpected");





 190 
 191   // Before returning the chunk, attempt to commit it according to the handout rules.
 192   // If that fails, we ignore the error and return the uncommitted chunk.
 193   if (commit_chunk_before_handout(c) == false) {
 194     log_info(gc, metaspace)("Failed to commit chunk prior to handout.");






 195   }

 196 
 197   return c;
 198 
 199 } // ChunkManager::get_chunk
 200 





 201 
 202 // Return a single chunk to the ChunkManager and adjust accounting. May merge chunk
 203 //  with neighbors.
 204 // Happens after a Classloader was unloaded and releases its metaspace chunks.
 205 // !! Note: this may invalidate the chunk. Do not access the chunk after
 206 //    this function returns !!
 207 void ChunkManager::return_chunk(Metachunk* c) {


















 208 
 209   assert_lock_strong(MetaspaceExpand_lock);
 210   DEBUG_ONLY(c->verify(false);)
 211 
 212   const chklvl_t orig_lvl = c->level();
 213 
 214   int num_merged[chklvl::NUM_CHUNK_LEVELS] = { 0 };
 215   Metachunk* c2 = c->vsnode()->merge(c, num_merged);




 216 
 217   if (c2 != NULL) {
 218     DEBUG_ONLY(c2->verify(false));
































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

 232       }
 233     }
 234     _total_word_size.decrement_by(size_chunks_removed);
 235 
 236     c = c2;
 237   }
 238 
 239   return_chunk_simple(c);






 240 
 241 }
 242 



























 243 
 244 ChunkManager* ChunkManager::_chunkmanager_class = NULL;
 245 ChunkManager* ChunkManager::_chunkmanager_nonclass = NULL;
 246 
 247 static void ChunkManager::initialize(ChunkManager* chunkmanager_class, ChunkManager* chunkmanager_nonclass) {
 248   _chunkmanager_class = chunkmanager_class;
 249   _chunkmanager_nonclass = chunkmanager_nonclass;
 250 }
 251 
 252 } // namespace metaspace
 253 
 254 
 255 
--- EOF ---