src/share/vm/memory/metaspace.cpp

changeset 9058
8c3e62bb99f3
parent 9057
b0f7174de2c5
child 9063
777ace6655eb
     1.1 --- a/src/share/vm/memory/metaspace.cpp	Wed Sep 20 20:54:29 2017 -0400
     1.2 +++ b/src/share/vm/memory/metaspace.cpp	Mon Dec 11 02:39:24 2017 -0800
     1.3 @@ -531,9 +531,8 @@
     1.4  
     1.5    size_t free_bytes();
     1.6  
     1.7 -  Metachunk* get_new_chunk(size_t word_size,
     1.8 -                           size_t grow_chunks_by_words,
     1.9 -                           size_t medium_chunk_bunch);
    1.10 +  Metachunk* get_new_chunk(size_t chunk_word_size,
    1.11 +                           size_t suggested_commit_granularity);
    1.12  
    1.13    bool expand_node_by(VirtualSpaceNode* node,
    1.14                        size_t min_words,
    1.15 @@ -687,15 +686,22 @@
    1.16      MediumChunkMultiple = 4
    1.17    };
    1.18  
    1.19 -  bool is_class() { return _mdtype == Metaspace::ClassType; }
    1.20 +  static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; }
    1.21 +  static size_t small_chunk_size(bool is_class)       { return is_class ? ClassSmallChunk : SmallChunk; }
    1.22 +  static size_t medium_chunk_size(bool is_class)      { return is_class ? ClassMediumChunk : MediumChunk; }
    1.23 +
    1.24 +  static size_t smallest_chunk_size(bool is_class)    { return specialized_chunk_size(is_class); }
    1.25  
    1.26    // Accessors
    1.27 -  size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; }
    1.28 -  size_t small_chunk_size()       { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
    1.29 -  size_t medium_chunk_size()      { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
    1.30 -  size_t medium_chunk_bunch()     { return medium_chunk_size() * MediumChunkMultiple; }
    1.31 -
    1.32 -  size_t smallest_chunk_size()  { return specialized_chunk_size(); }
    1.33 +  bool is_class() const { return _mdtype == Metaspace::ClassType; }
    1.34 +
    1.35 +  size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); }
    1.36 +  size_t small_chunk_size()       const { return small_chunk_size(is_class()); }
    1.37 +  size_t medium_chunk_size()      const { return medium_chunk_size(is_class()); }
    1.38 +
    1.39 +  size_t smallest_chunk_size()    const { return smallest_chunk_size(is_class()); }
    1.40 +
    1.41 +  size_t medium_chunk_bunch()     const { return medium_chunk_size() * MediumChunkMultiple; }
    1.42  
    1.43    size_t allocated_blocks_words() const { return _allocated_blocks_words; }
    1.44    size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
    1.45 @@ -718,10 +724,13 @@
    1.46    // decremented for all the Metachunks in-use by this SpaceManager.
    1.47    void dec_total_from_size_metrics();
    1.48  
    1.49 -  // Set the sizes for the initial chunks.
    1.50 -  void get_initial_chunk_sizes(Metaspace::MetaspaceType type,
    1.51 -                               size_t* chunk_word_size,
    1.52 -                               size_t* class_chunk_word_size);
    1.53 +  // Adjust the initial chunk size to match one of the fixed chunk list sizes,
    1.54 +  // or return the unadjusted size if the requested size is humongous.
    1.55 +  static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space);
    1.56 +  size_t adjust_initial_chunk_size(size_t requested) const;
    1.57 +
    1.58 +  // Get the initial chunks size for this metaspace type.
    1.59 +  size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
    1.60  
    1.61    size_t sum_capacity_in_chunks_in_use() const;
    1.62    size_t sum_used_in_chunks_in_use() const;
    1.63 @@ -732,7 +741,7 @@
    1.64    size_t sum_count_in_chunks_in_use();
    1.65    size_t sum_count_in_chunks_in_use(ChunkIndex i);
    1.66  
    1.67 -  Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words);
    1.68 +  Metachunk* get_new_chunk(size_t chunk_word_size);
    1.69  
    1.70    // Block allocation and deallocation.
    1.71    // Allocates a block from the current chunk
    1.72 @@ -1319,12 +1328,10 @@
    1.73    return false;
    1.74  }
    1.75  
    1.76 -Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
    1.77 -                                           size_t grow_chunks_by_words,
    1.78 -                                           size_t medium_chunk_bunch) {
    1.79 +Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) {
    1.80  
    1.81    // Allocate a chunk out of the current virtual space.
    1.82 -  Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
    1.83 +  Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size);
    1.84  
    1.85    if (next != NULL) {
    1.86      return next;
    1.87 @@ -1333,8 +1340,8 @@
    1.88    // The expand amount is currently only determined by the requested sizes
    1.89    // and not how much committed memory is left in the current virtual space.
    1.90  
    1.91 -  size_t min_word_size       = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words());
    1.92 -  size_t preferred_word_size = align_size_up(medium_chunk_bunch,   Metaspace::commit_alignment_words());
    1.93 +  size_t min_word_size       = align_size_up(chunk_word_size,              Metaspace::commit_alignment_words());
    1.94 +  size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words());
    1.95    if (min_word_size >= preferred_word_size) {
    1.96      // Can happen when humongous chunks are allocated.
    1.97      preferred_word_size = min_word_size;
    1.98 @@ -1342,7 +1349,7 @@
    1.99  
   1.100    bool expanded = expand_by(min_word_size, preferred_word_size);
   1.101    if (expanded) {
   1.102 -    next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
   1.103 +    next = current_virtual_space()->get_chunk_vs(chunk_word_size);
   1.104      assert(next != NULL, "The allocation was expected to succeed after the expansion");
   1.105    }
   1.106  
   1.107 @@ -1883,36 +1890,58 @@
   1.108  
   1.109  // SpaceManager methods
   1.110  
   1.111 -void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type,
   1.112 -                                           size_t* chunk_word_size,
   1.113 -                                           size_t* class_chunk_word_size) {
   1.114 -  switch (type) {
   1.115 -  case Metaspace::BootMetaspaceType:
   1.116 -    *chunk_word_size = Metaspace::first_chunk_word_size();
   1.117 -    *class_chunk_word_size = Metaspace::first_class_chunk_word_size();
   1.118 -    break;
   1.119 -  case Metaspace::ROMetaspaceType:
   1.120 -    *chunk_word_size = SharedReadOnlySize / wordSize;
   1.121 -    *class_chunk_word_size = ClassSpecializedChunk;
   1.122 -    break;
   1.123 -  case Metaspace::ReadWriteMetaspaceType:
   1.124 -    *chunk_word_size = SharedReadWriteSize / wordSize;
   1.125 -    *class_chunk_word_size = ClassSpecializedChunk;
   1.126 -    break;
   1.127 -  case Metaspace::AnonymousMetaspaceType:
   1.128 -  case Metaspace::ReflectionMetaspaceType:
   1.129 -    *chunk_word_size = SpecializedChunk;
   1.130 -    *class_chunk_word_size = ClassSpecializedChunk;
   1.131 -    break;
   1.132 -  default:
   1.133 -    *chunk_word_size = SmallChunk;
   1.134 -    *class_chunk_word_size = ClassSmallChunk;
   1.135 -    break;
   1.136 +size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) {
   1.137 +  size_t chunk_sizes[] = {
   1.138 +      specialized_chunk_size(is_class_space),
   1.139 +      small_chunk_size(is_class_space),
   1.140 +      medium_chunk_size(is_class_space)
   1.141 +  };
   1.142 +
   1.143 +  // Adjust up to one of the fixed chunk sizes ...
   1.144 +  for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) {
   1.145 +    if (requested <= chunk_sizes[i]) {
   1.146 +      return chunk_sizes[i];
   1.147 +    }
   1.148    }
   1.149 -  assert(*chunk_word_size != 0 && *class_chunk_word_size != 0,
   1.150 -    err_msg("Initial chunks sizes bad: data  " SIZE_FORMAT
   1.151 -            " class " SIZE_FORMAT,
   1.152 -            *chunk_word_size, *class_chunk_word_size));
   1.153 +
   1.154 +  // ... or return the size as a humongous chunk.
   1.155 +  return requested;
   1.156 +}
   1.157 +
   1.158 +size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const {
   1.159 +  return adjust_initial_chunk_size(requested, is_class());
   1.160 +}
   1.161 +
   1.162 +size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const {
   1.163 +  size_t requested;
   1.164 +
   1.165 +  if (is_class()) {
   1.166 +    switch (type) {
   1.167 +    case Metaspace::BootMetaspaceType:       requested = Metaspace::first_class_chunk_word_size(); break;
   1.168 +    case Metaspace::ROMetaspaceType:         requested = ClassSpecializedChunk; break;
   1.169 +    case Metaspace::ReadWriteMetaspaceType:  requested = ClassSpecializedChunk; break;
   1.170 +    case Metaspace::AnonymousMetaspaceType:  requested = ClassSpecializedChunk; break;
   1.171 +    case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break;
   1.172 +    default:                                 requested = ClassSmallChunk; break;
   1.173 +    }
   1.174 +  } else {
   1.175 +    switch (type) {
   1.176 +    case Metaspace::BootMetaspaceType:       requested = Metaspace::first_chunk_word_size(); break;
   1.177 +    case Metaspace::ROMetaspaceType:         requested = SharedReadOnlySize / wordSize; break;
   1.178 +    case Metaspace::ReadWriteMetaspaceType:  requested = SharedReadWriteSize / wordSize; break;
   1.179 +    case Metaspace::AnonymousMetaspaceType:  requested = SpecializedChunk; break;
   1.180 +    case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break;
   1.181 +    default:                                 requested = SmallChunk; break;
   1.182 +    }
   1.183 +  }
   1.184 +
   1.185 +  // Adjust to one of the fixed chunk sizes (unless humongous)
   1.186 +  const size_t adjusted = adjust_initial_chunk_size(requested);
   1.187 +
   1.188 +  assert(adjusted != 0, err_msg("Incorrect initial chunk size. Requested: "
   1.189 +         SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted));
   1.190 +
   1.191 +  return adjusted;
   1.192  }
   1.193  
   1.194  size_t SpaceManager::sum_free_in_chunks_in_use() const {
   1.195 @@ -2102,8 +2131,8 @@
   1.196    }
   1.197  
   1.198    // Get another chunk out of the virtual space
   1.199 -  size_t grow_chunks_by_words = calc_chunk_size(word_size);
   1.200 -  Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words);
   1.201 +  size_t chunk_word_size = calc_chunk_size(word_size);
   1.202 +  Metachunk* next = get_new_chunk(chunk_word_size);
   1.203  
   1.204    MetaWord* mem = NULL;
   1.205  
   1.206 @@ -2412,14 +2441,12 @@
   1.207    }
   1.208  }
   1.209  
   1.210 -Metachunk* SpaceManager::get_new_chunk(size_t word_size,
   1.211 -                                       size_t grow_chunks_by_words) {
   1.212 +Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) {
   1.213    // Get a chunk from the chunk freelist
   1.214 -  Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
   1.215 +  Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size);
   1.216  
   1.217    if (next == NULL) {
   1.218 -    next = vs_list()->get_new_chunk(word_size,
   1.219 -                                    grow_chunks_by_words,
   1.220 +    next = vs_list()->get_new_chunk(chunk_word_size,
   1.221                                      medium_chunk_bunch());
   1.222    }
   1.223  
   1.224 @@ -3085,7 +3112,7 @@
   1.225           err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize));
   1.226    assert(using_class_space(), "Must be using class space");
   1.227    _class_space_list = new VirtualSpaceList(rs);
   1.228 -  _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk);
   1.229 +  _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
   1.230  
   1.231    if (!_class_space_list->initialization_succeeded()) {
   1.232      vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
   1.233 @@ -3286,66 +3313,62 @@
   1.234    MetaspaceGC::post_initialize();
   1.235  }
   1.236  
   1.237 -Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype,
   1.238 -                                               size_t chunk_word_size,
   1.239 -                                               size_t chunk_bunch) {
   1.240 +void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) {
   1.241 +  Metachunk* chunk = get_initialization_chunk(type, mdtype);
   1.242 +  if (chunk != NULL) {
   1.243 +    // Add to this manager's list of chunks in use and current_chunk().
   1.244 +    get_space_manager(mdtype)->add_chunk(chunk, true);
   1.245 +  }
   1.246 +}
   1.247 +
   1.248 +Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) {
   1.249 +  size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
   1.250 +
   1.251    // Get a chunk from the chunk freelist
   1.252    Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
   1.253 -  if (chunk != NULL) {
   1.254 -    return chunk;
   1.255 +
   1.256 +  if (chunk == NULL) {
   1.257 +    chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size,
   1.258 +                                                  get_space_manager(mdtype)->medium_chunk_bunch());
   1.259    }
   1.260  
   1.261 -  return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch);
   1.262 +  // For dumping shared archive, report error if allocation has failed.
   1.263 +  if (DumpSharedSpaces && chunk == NULL) {
   1.264 +    report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord);
   1.265 +  }
   1.266 +
   1.267 +  return chunk;
   1.268  }
   1.269  
   1.270 +void Metaspace::verify_global_initialization() {
   1.271 +  assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized");
   1.272 +  assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized");
   1.273 +
   1.274 +  if (using_class_space()) {
   1.275 +    assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized");
   1.276 +    assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized");
   1.277 +  }
   1.278 +}
   1.279 +
   1.280  void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
   1.281 -
   1.282 -  assert(space_list() != NULL,
   1.283 -    "Metadata VirtualSpaceList has not been initialized");
   1.284 -  assert(chunk_manager_metadata() != NULL,
   1.285 -    "Metadata ChunkManager has not been initialized");
   1.286 -
   1.287 +  verify_global_initialization();
   1.288 +
   1.289 +  // Allocate SpaceManager for metadata objects.
   1.290    _vsm = new SpaceManager(NonClassType, lock);
   1.291 -  if (_vsm == NULL) {
   1.292 -    return;
   1.293 -  }
   1.294 -  size_t word_size;
   1.295 -  size_t class_word_size;
   1.296 -  vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size);
   1.297  
   1.298    if (using_class_space()) {
   1.299 -  assert(class_space_list() != NULL,
   1.300 -    "Class VirtualSpaceList has not been initialized");
   1.301 -  assert(chunk_manager_class() != NULL,
   1.302 -    "Class ChunkManager has not been initialized");
   1.303 -
   1.304      // Allocate SpaceManager for classes.
   1.305      _class_vsm = new SpaceManager(ClassType, lock);
   1.306 -    if (_class_vsm == NULL) {
   1.307 -      return;
   1.308 -    }
   1.309    }
   1.310  
   1.311    MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
   1.312  
   1.313    // Allocate chunk for metadata objects
   1.314 -  Metachunk* new_chunk = get_initialization_chunk(NonClassType,
   1.315 -                                                  word_size,
   1.316 -                                                  vsm()->medium_chunk_bunch());
   1.317 -  assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
   1.318 -  if (new_chunk != NULL) {
   1.319 -    // Add to this manager's list of chunks in use and current_chunk().
   1.320 -    vsm()->add_chunk(new_chunk, true);
   1.321 -  }
   1.322 +  initialize_first_chunk(type, NonClassType);
   1.323  
   1.324    // Allocate chunk for class metadata objects
   1.325    if (using_class_space()) {
   1.326 -    Metachunk* class_chunk = get_initialization_chunk(ClassType,
   1.327 -                                                      class_word_size,
   1.328 -                                                      class_vsm()->medium_chunk_bunch());
   1.329 -    if (class_chunk != NULL) {
   1.330 -      class_vsm()->add_chunk(class_chunk, true);
   1.331 -    }
   1.332 +    initialize_first_chunk(type, ClassType);
   1.333    }
   1.334  
   1.335    _alloc_record_head = NULL;
   1.336 @@ -3772,7 +3795,7 @@
   1.337      // vm_allocation_granularity aligned on Windows.
   1.338      size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
   1.339      large_size += (os::vm_page_size()/BytesPerWord);
   1.340 -    vs_list->get_new_chunk(large_size, large_size, 0);
   1.341 +    vs_list->get_new_chunk(large_size, 0);
   1.342    }
   1.343  
   1.344    static void test() {
   1.345 @@ -3947,4 +3970,54 @@
   1.346    TestVirtualSpaceNodeTest::test();
   1.347    TestVirtualSpaceNodeTest::test_is_available();
   1.348  }
   1.349 +
   1.350 +// The following test is placed here instead of a gtest / unittest file
   1.351 +// because the ChunkManager class is only available in this file.
   1.352 +class SpaceManagerTest : AllStatic {
   1.353 +  friend void SpaceManager_test_adjust_initial_chunk_size();
   1.354 +
   1.355 +  static void test_adjust_initial_chunk_size(bool is_class) {
   1.356 +    const size_t smallest = SpaceManager::smallest_chunk_size(is_class);
   1.357 +    const size_t normal   = SpaceManager::small_chunk_size(is_class);
   1.358 +    const size_t medium   = SpaceManager::medium_chunk_size(is_class);
   1.359 +
   1.360 +#define test_adjust_initial_chunk_size(value, expected, is_class_value)          \
   1.361 +    do {                                                                         \
   1.362 +      size_t v = value;                                                          \
   1.363 +      size_t e = expected;                                                       \
   1.364 +      assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e,  \
   1.365 +             err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v));      \
   1.366 +    } while (0)
   1.367 +
   1.368 +    // Smallest (specialized)
   1.369 +    test_adjust_initial_chunk_size(1,            smallest, is_class);
   1.370 +    test_adjust_initial_chunk_size(smallest - 1, smallest, is_class);
   1.371 +    test_adjust_initial_chunk_size(smallest,     smallest, is_class);
   1.372 +
   1.373 +    // Small
   1.374 +    test_adjust_initial_chunk_size(smallest + 1, normal, is_class);
   1.375 +    test_adjust_initial_chunk_size(normal - 1,   normal, is_class);
   1.376 +    test_adjust_initial_chunk_size(normal,       normal, is_class);
   1.377 +
   1.378 +    // Medium
   1.379 +    test_adjust_initial_chunk_size(normal + 1, medium, is_class);
   1.380 +    test_adjust_initial_chunk_size(medium - 1, medium, is_class);
   1.381 +    test_adjust_initial_chunk_size(medium,     medium, is_class);
   1.382 +
   1.383 +    // Humongous
   1.384 +    test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class);
   1.385 +
   1.386 +#undef test_adjust_initial_chunk_size
   1.387 +  }
   1.388 +
   1.389 +  static void test_adjust_initial_chunk_size() {
   1.390 +    test_adjust_initial_chunk_size(false);
   1.391 +    test_adjust_initial_chunk_size(true);
   1.392 +  }
   1.393 +};
   1.394 +
   1.395 +void SpaceManager_test_adjust_initial_chunk_size() {
   1.396 +  SpaceManagerTest::test_adjust_initial_chunk_size();
   1.397 +}
   1.398 +
   1.399  #endif

mercurial