8199431: Split up class Metaspace into a static and a non-static part
authorstuefe
Thu, 15 Mar 2018 07:15:39 +0100
changeset 49401 0c71baee49a7
parent 49400 d2dd7e7d2044
child 49402 64156c70746c
8199431: Split up class Metaspace into a static and a non-static part Reviewed-by: coleenp, adinn, zgu
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/classfile/classLoaderData.hpp
src/hotspot/share/classfile/classLoaderStats.cpp
src/hotspot/share/memory/metaspace.cpp
src/hotspot/share/memory/metaspace.hpp
test/hotspot/gtest/memory/test_metaspace_allocation.cpp
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Thu Mar 15 07:15:39 2018 +0100
@@ -667,7 +667,7 @@
   }
 
   // release the metaspace
-  Metaspace *m = _metaspace;
+  ClassLoaderMetaspace *m = _metaspace;
   if (m != NULL) {
     _metaspace = NULL;
     delete m;
@@ -721,26 +721,26 @@
   return is_builtin_class_loader_data() && !is_anonymous();
 }
 
-Metaspace* ClassLoaderData::metaspace_non_null() {
+ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() {
   // If the metaspace has not been allocated, create a new one.  Might want
   // to create smaller arena for Reflection class loaders also.
   // The reason for the delayed allocation is because some class loaders are
   // simply for delegating with no metadata of their own.
   // Lock-free access requires load_acquire.
-  Metaspace* metaspace = OrderAccess::load_acquire(&_metaspace);
+  ClassLoaderMetaspace* metaspace = OrderAccess::load_acquire(&_metaspace);
   if (metaspace == NULL) {
     MutexLockerEx ml(_metaspace_lock,  Mutex::_no_safepoint_check_flag);
     // Check if _metaspace got allocated while we were waiting for this lock.
     if ((metaspace = _metaspace) == NULL) {
       if (this == the_null_class_loader_data()) {
         assert (class_loader() == NULL, "Must be");
-        metaspace = new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
+        metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
       } else if (is_anonymous()) {
-        metaspace = new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType);
+        metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType);
       } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
-        metaspace = new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
+        metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
       } else {
-        metaspace = new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
+        metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::StandardMetaspaceType);
       }
       // Ensure _metaspace is stable, since it is examined without a lock
       OrderAccess::release_store(&_metaspace, metaspace);
@@ -1180,7 +1180,8 @@
 bool ClassLoaderDataGraph::unload_list_contains(const void* x) {
   assert(SafepointSynchronize::is_at_safepoint(), "only safe to call at safepoint");
   for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) {
-    if (cld->metaspace_or_null() != NULL && cld->metaspace_or_null()->contains(x)) {
+    // Needs fixing, see JDK-8199007.
+    if (cld->metaspace_or_null() != NULL && Metaspace::contains(x)) {
       return true;
     }
   }
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Thu Mar 15 07:15:39 2018 +0100
@@ -223,7 +223,7 @@
   oop _class_loader;          // oop used to uniquely identify a class loader
                               // class loader or a canonical class path
 
-  Metaspace * volatile _metaspace;  // Meta-space where meta-data defined by the
+  ClassLoaderMetaspace * volatile _metaspace;  // Meta-space where meta-data defined by the
                                     // classes in the class loader are allocated.
   Mutex* _metaspace_lock;  // Locks the metaspace for allocations and setup.
   bool _unloading;         // true if this class loader goes away
@@ -264,11 +264,6 @@
   // Support for walking class loader data objects
   ClassLoaderData* _next; /// Next loader_datas created
 
-  // ReadOnly and ReadWrite metaspaces (static because only on the null
-  // class loader for now).
-  static Metaspace* _ro_metaspace;
-  static Metaspace* _rw_metaspace;
-
   TRACE_DEFINE_TRACE_ID_FIELD;
 
   void set_next(ClassLoaderData* next) { _next = next; }
@@ -316,7 +311,7 @@
   bool is_alive(BoolObjectClosure* is_alive_closure) const;
 
   // Accessors
-  Metaspace* metaspace_or_null() const     { return _metaspace; }
+  ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; }
 
   static ClassLoaderData* the_null_class_loader_data() {
     return _the_null_class_loader_data;
@@ -351,7 +346,7 @@
 
   // The Metaspace is created lazily so may be NULL.  This
   // method will allocate a Metaspace if needed.
-  Metaspace* metaspace_non_null();
+  ClassLoaderMetaspace* metaspace_non_null();
 
   oop class_loader() const      { return _class_loader; }
 
@@ -426,9 +421,9 @@
   ClassLoaderDataGraphMetaspaceIterator();
   ~ClassLoaderDataGraphMetaspaceIterator();
   bool repeat() { return _data != NULL; }
-  Metaspace* get_next() {
+  ClassLoaderMetaspace* get_next() {
     assert(_data != NULL, "Should not be NULL in call to the iterator");
-    Metaspace* result = _data->metaspace_or_null();
+    ClassLoaderMetaspace* result = _data->metaspace_or_null();
     _data = _data->next();
     // This result might be NULL for class loaders without metaspace
     // yet.  It would be nice to return only non-null results but
--- a/src/hotspot/share/classfile/classLoaderStats.cpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/src/hotspot/share/classfile/classLoaderStats.cpp	Thu Mar 15 07:15:39 2018 +0100
@@ -76,7 +76,7 @@
   }
   _total_classes += csc._num_classes;
 
-  Metaspace* ms = cld->metaspace_or_null();
+  ClassLoaderMetaspace* ms = cld->metaspace_or_null();
   if (ms != NULL) {
     if(cld->is_anonymous()) {
       cls->_anon_chunk_sz += ms->allocated_chunks_bytes();
--- a/src/hotspot/share/memory/metaspace.cpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/src/hotspot/share/memory/metaspace.cpp	Thu Mar 15 07:15:39 2018 +0100
@@ -1225,7 +1225,7 @@
 
 //  SpaceManager - used by Metaspace to handle allocations
 class SpaceManager : public CHeapObj<mtClass> {
-  friend class Metaspace;
+  friend class ClassLoaderMetaspace;
   friend class Metadebug;
 
  private:
@@ -3838,7 +3838,7 @@
   size_t used = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
-    Metaspace* msp = iter.get_next();
+    ClassLoaderMetaspace* msp = iter.get_next();
     // Sum allocated_blocks_words for each metaspace
     if (msp != NULL) {
       used += msp->used_words_slow(mdtype);
@@ -3851,7 +3851,7 @@
   size_t free = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
-    Metaspace* msp = iter.get_next();
+    ClassLoaderMetaspace* msp = iter.get_next();
     if (msp != NULL) {
       free += msp->free_words_slow(mdtype);
     }
@@ -3868,7 +3868,7 @@
   size_t capacity = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
-    Metaspace* msp = iter.get_next();
+    ClassLoaderMetaspace* msp = iter.get_next();
     if (msp != NULL) {
       capacity += msp->capacity_words_slow(mdtype);
     }
@@ -4001,7 +4001,7 @@
   size_t cls_specialized_count = 0, cls_small_count = 0, cls_medium_count = 0, cls_humongous_count = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
-    Metaspace* msp = iter.get_next();
+    ClassLoaderMetaspace* msp = iter.get_next();
     if (msp != NULL) {
       cls_specialized_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SpecializedIndex);
       cls_specialized_count += msp->class_vsm()->sum_count_in_chunks_in_use(SpecializedIndex);
@@ -4028,7 +4028,7 @@
 
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
-    Metaspace* msp = iter.get_next();
+    ClassLoaderMetaspace* msp = iter.get_next();
     if (msp != NULL) {
       specialized_waste += msp->vsm()->sum_waste_in_chunks_in_use(SpecializedIndex);
       specialized_count += msp->vsm()->sum_count_in_chunks_in_use(SpecializedIndex);
@@ -4113,7 +4113,7 @@
     assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
 
     if (cld->is_unloading()) return;
-    Metaspace* msp = cld->metaspace_or_null();
+    ClassLoaderMetaspace* msp = cld->metaspace_or_null();
     if (msp == NULL) {
       return;
     }
@@ -4132,11 +4132,11 @@
   }
 
 private:
-  void print_metaspace(Metaspace* msp, bool anonymous);
+  void print_metaspace(ClassLoaderMetaspace* msp, bool anonymous);
   void print_summary() const;
 };
 
-void PrintCLDMetaspaceInfoClosure::print_metaspace(Metaspace* msp, bool anonymous){
+void PrintCLDMetaspaceInfoClosure::print_metaspace(ClassLoaderMetaspace* msp, bool anonymous){
   assert(msp != NULL, "Sanity");
   SpaceManager* vsm = msp->vsm();
   const char* unit = scale_unit(_scale);
@@ -4335,17 +4335,6 @@
 size_t Metaspace::_commit_alignment = 0;
 size_t Metaspace::_reserve_alignment = 0;
 
-Metaspace::Metaspace(Mutex* lock, MetaspaceType type) {
-  initialize(lock, type);
-}
-
-Metaspace::~Metaspace() {
-  delete _vsm;
-  if (using_class_space()) {
-    delete _class_vsm;
-  }
-}
-
 VirtualSpaceList* Metaspace::_space_list = NULL;
 VirtualSpaceList* Metaspace::_class_space_list = NULL;
 
@@ -4680,28 +4669,6 @@
   MetaspaceGC::post_initialize();
 }
 
-void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) {
-  Metachunk* chunk = get_initialization_chunk(type, mdtype);
-  if (chunk != NULL) {
-    // Add to this manager's list of chunks in use and current_chunk().
-    get_space_manager(mdtype)->add_chunk(chunk, true);
-  }
-}
-
-Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) {
-  size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
-
-  // Get a chunk from the chunk freelist
-  Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
-
-  if (chunk == NULL) {
-    chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size,
-                                                  get_space_manager(mdtype)->medium_chunk_bunch());
-  }
-
-  return chunk;
-}
-
 void Metaspace::verify_global_initialization() {
   assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized");
   assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized");
@@ -4712,132 +4679,11 @@
   }
 }
 
-void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
-  verify_global_initialization();
-
-  // Allocate SpaceManager for metadata objects.
-  _vsm = new SpaceManager(NonClassType, type, lock);
-
-  if (using_class_space()) {
-    // Allocate SpaceManager for classes.
-    _class_vsm = new SpaceManager(ClassType, type, lock);
-  }
-
-  MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
-
-  // Allocate chunk for metadata objects
-  initialize_first_chunk(type, NonClassType);
-
-  // Allocate chunk for class metadata objects
-  if (using_class_space()) {
-    initialize_first_chunk(type, ClassType);
-  }
-}
-
 size_t Metaspace::align_word_size_up(size_t word_size) {
   size_t byte_size = word_size * wordSize;
   return ReservedSpace::allocation_align_size_up(byte_size) / wordSize;
 }
 
-MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) {
-  assert(!_frozen, "sanity");
-  // Don't use class_vsm() unless UseCompressedClassPointers is true.
-  if (is_class_space_allocation(mdtype)) {
-    return  class_vsm()->allocate(word_size);
-  } else {
-    return  vsm()->allocate(word_size);
-  }
-}
-
-MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) {
-  assert(!_frozen, "sanity");
-  size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord);
-  assert(delta_bytes > 0, "Must be");
-
-  size_t before = 0;
-  size_t after = 0;
-  MetaWord* res;
-  bool incremented;
-
-  // Each thread increments the HWM at most once. Even if the thread fails to increment
-  // the HWM, an allocation is still attempted. This is because another thread must then
-  // have incremented the HWM and therefore the allocation might still succeed.
-  do {
-    incremented = MetaspaceGC::inc_capacity_until_GC(delta_bytes, &after, &before);
-    res = allocate(word_size, mdtype);
-  } while (!incremented && res == NULL);
-
-  if (incremented) {
-    tracer()->report_gc_threshold(before, after,
-                                  MetaspaceGCThresholdUpdater::ExpandAndAllocate);
-    log_trace(gc, metaspace)("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before, after);
-  }
-
-  return res;
-}
-
-size_t Metaspace::used_words_slow(MetadataType mdtype) const {
-  if (mdtype == ClassType) {
-    return using_class_space() ? class_vsm()->sum_used_in_chunks_in_use() : 0;
-  } else {
-    return vsm()->sum_used_in_chunks_in_use();  // includes overhead!
-  }
-}
-
-size_t Metaspace::free_words_slow(MetadataType mdtype) const {
-  assert(!_frozen, "sanity");
-  if (mdtype == ClassType) {
-    return using_class_space() ? class_vsm()->sum_free_in_chunks_in_use() : 0;
-  } else {
-    return vsm()->sum_free_in_chunks_in_use();
-  }
-}
-
-// Space capacity in the Metaspace.  It includes
-// space in the list of chunks from which allocations
-// have been made. Don't include space in the global freelist and
-// in the space available in the dictionary which
-// is already counted in some chunk.
-size_t Metaspace::capacity_words_slow(MetadataType mdtype) const {
-  if (mdtype == ClassType) {
-    return using_class_space() ? class_vsm()->sum_capacity_in_chunks_in_use() : 0;
-  } else {
-    return vsm()->sum_capacity_in_chunks_in_use();
-  }
-}
-
-size_t Metaspace::used_bytes_slow(MetadataType mdtype) const {
-  return used_words_slow(mdtype) * BytesPerWord;
-}
-
-size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const {
-  return capacity_words_slow(mdtype) * BytesPerWord;
-}
-
-size_t Metaspace::allocated_blocks_bytes() const {
-  return vsm()->allocated_blocks_bytes() +
-      (using_class_space() ? class_vsm()->allocated_blocks_bytes() : 0);
-}
-
-size_t Metaspace::allocated_chunks_bytes() const {
-  return vsm()->allocated_chunks_bytes() +
-      (using_class_space() ? class_vsm()->allocated_chunks_bytes() : 0);
-}
-
-void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
-  assert(!_frozen, "sanity");
-  assert(!SafepointSynchronize::is_at_safepoint()
-         || Thread::current()->is_VM_thread(), "should be the VM thread");
-
-  MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
-
-  if (is_class && using_class_space()) {
-    class_vsm()->deallocate(ptr, word_size);
-  } else {
-    vsm()->deallocate(ptr, word_size);
-  }
-}
-
 MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
                               MetaspaceObj::Type type, TRAPS) {
   assert(!_frozen, "sanity");
@@ -4882,11 +4728,6 @@
   return result;
 }
 
-size_t Metaspace::class_chunk_size(size_t word_size) {
-  assert(using_class_space(), "Has to use class space");
-  return class_vsm()->calc_chunk_size(word_size);
-}
-
 void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type, MetadataType mdtype, TRAPS) {
   tracer()->report_metadata_oom(loader_data, word_size, type, mdtype);
 
@@ -4910,7 +4751,7 @@
 
   bool out_of_compressed_class_space = false;
   if (is_class_space_allocation(mdtype)) {
-    Metaspace* metaspace = loader_data->metaspace_non_null();
+    ClassLoaderMetaspace* metaspace = loader_data->metaspace_non_null();
     out_of_compressed_class_space =
       MetaspaceUtils::committed_bytes(Metaspace::ClassType) +
       (metaspace->class_chunk_size(word_size) * BytesPerWord) >
@@ -4963,16 +4804,6 @@
   }
 }
 
-void Metaspace::print_on(outputStream* out) const {
-  // Print both class virtual space counts and metaspace.
-  if (Verbose) {
-    vsm()->print_on(out);
-    if (using_class_space()) {
-      class_vsm()->print_on(out);
-    }
-  }
-}
-
 bool Metaspace::contains(const void* ptr) {
   if (MetaspaceShared::is_in_shared_metaspace(ptr)) {
     return true;
@@ -4988,22 +4819,194 @@
   return get_space_list(NonClassType)->contains(ptr);
 }
 
-void Metaspace::verify() {
+// ClassLoaderMetaspace
+
+ClassLoaderMetaspace::ClassLoaderMetaspace(Mutex* lock, Metaspace::MetaspaceType type) {
+  initialize(lock, type);
+}
+
+ClassLoaderMetaspace::~ClassLoaderMetaspace() {
+  delete _vsm;
+  if (Metaspace::using_class_space()) {
+    delete _class_vsm;
+  }
+}
+void ClassLoaderMetaspace::initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype) {
+  Metachunk* chunk = get_initialization_chunk(type, mdtype);
+  if (chunk != NULL) {
+    // Add to this manager's list of chunks in use and current_chunk().
+    get_space_manager(mdtype)->add_chunk(chunk, true);
+  }
+}
+
+Metachunk* ClassLoaderMetaspace::get_initialization_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype) {
+  size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
+
+  // Get a chunk from the chunk freelist
+  Metachunk* chunk = Metaspace::get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
+
+  if (chunk == NULL) {
+    chunk = Metaspace::get_space_list(mdtype)->get_new_chunk(chunk_word_size,
+                                                  get_space_manager(mdtype)->medium_chunk_bunch());
+  }
+
+  return chunk;
+}
+
+void ClassLoaderMetaspace::initialize(Mutex* lock, Metaspace::MetaspaceType type) {
+  Metaspace::verify_global_initialization();
+
+  // Allocate SpaceManager for metadata objects.
+  _vsm = new SpaceManager(Metaspace::NonClassType, type, lock);
+
+  if (Metaspace::using_class_space()) {
+    // Allocate SpaceManager for classes.
+    _class_vsm = new SpaceManager(Metaspace::ClassType, type, lock);
+  }
+
+  MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
+
+  // Allocate chunk for metadata objects
+  initialize_first_chunk(type, Metaspace::NonClassType);
+
+  // Allocate chunk for class metadata objects
+  if (Metaspace::using_class_space()) {
+    initialize_first_chunk(type, Metaspace::ClassType);
+  }
+}
+
+MetaWord* ClassLoaderMetaspace::allocate(size_t word_size, Metaspace::MetadataType mdtype) {
+  Metaspace::assert_not_frozen();
+  // Don't use class_vsm() unless UseCompressedClassPointers is true.
+  if (Metaspace::is_class_space_allocation(mdtype)) {
+    return  class_vsm()->allocate(word_size);
+  } else {
+    return  vsm()->allocate(word_size);
+  }
+}
+
+MetaWord* ClassLoaderMetaspace::expand_and_allocate(size_t word_size, Metaspace::MetadataType mdtype) {
+  Metaspace::assert_not_frozen();
+  size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord);
+  assert(delta_bytes > 0, "Must be");
+
+  size_t before = 0;
+  size_t after = 0;
+  MetaWord* res;
+  bool incremented;
+
+  // Each thread increments the HWM at most once. Even if the thread fails to increment
+  // the HWM, an allocation is still attempted. This is because another thread must then
+  // have incremented the HWM and therefore the allocation might still succeed.
+  do {
+    incremented = MetaspaceGC::inc_capacity_until_GC(delta_bytes, &after, &before);
+    res = allocate(word_size, mdtype);
+  } while (!incremented && res == NULL);
+
+  if (incremented) {
+    Metaspace::tracer()->report_gc_threshold(before, after,
+                                  MetaspaceGCThresholdUpdater::ExpandAndAllocate);
+    log_trace(gc, metaspace)("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before, after);
+  }
+
+  return res;
+}
+
+size_t ClassLoaderMetaspace::used_words_slow(Metaspace::MetadataType mdtype) const {
+  if (mdtype == Metaspace::ClassType) {
+    return Metaspace::using_class_space() ? class_vsm()->sum_used_in_chunks_in_use() : 0;
+  } else {
+    return vsm()->sum_used_in_chunks_in_use();  // includes overhead!
+  }
+}
+
+size_t ClassLoaderMetaspace::free_words_slow(Metaspace::MetadataType mdtype) const {
+  Metaspace::assert_not_frozen();
+  if (mdtype == Metaspace::ClassType) {
+    return Metaspace::using_class_space() ? class_vsm()->sum_free_in_chunks_in_use() : 0;
+  } else {
+    return vsm()->sum_free_in_chunks_in_use();
+  }
+}
+
+// Space capacity in the Metaspace.  It includes
+// space in the list of chunks from which allocations
+// have been made. Don't include space in the global freelist and
+// in the space available in the dictionary which
+// is already counted in some chunk.
+size_t ClassLoaderMetaspace::capacity_words_slow(Metaspace::MetadataType mdtype) const {
+  if (mdtype == Metaspace::ClassType) {
+    return Metaspace::using_class_space() ? class_vsm()->sum_capacity_in_chunks_in_use() : 0;
+  } else {
+    return vsm()->sum_capacity_in_chunks_in_use();
+  }
+}
+
+size_t ClassLoaderMetaspace::used_bytes_slow(Metaspace::MetadataType mdtype) const {
+  return used_words_slow(mdtype) * BytesPerWord;
+}
+
+size_t ClassLoaderMetaspace::capacity_bytes_slow(Metaspace::MetadataType mdtype) const {
+  return capacity_words_slow(mdtype) * BytesPerWord;
+}
+
+size_t ClassLoaderMetaspace::allocated_blocks_bytes() const {
+  return vsm()->allocated_blocks_bytes() +
+      (Metaspace::using_class_space() ? class_vsm()->allocated_blocks_bytes() : 0);
+}
+
+size_t ClassLoaderMetaspace::allocated_chunks_bytes() const {
+  return vsm()->allocated_chunks_bytes() +
+      (Metaspace::using_class_space() ? class_vsm()->allocated_chunks_bytes() : 0);
+}
+
+void ClassLoaderMetaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
+  Metaspace::assert_not_frozen();
+  assert(!SafepointSynchronize::is_at_safepoint()
+         || Thread::current()->is_VM_thread(), "should be the VM thread");
+
+  MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
+
+  if (is_class && Metaspace::using_class_space()) {
+    class_vsm()->deallocate(ptr, word_size);
+  } else {
+    vsm()->deallocate(ptr, word_size);
+  }
+}
+
+size_t ClassLoaderMetaspace::class_chunk_size(size_t word_size) {
+  assert(Metaspace::using_class_space(), "Has to use class space");
+  return class_vsm()->calc_chunk_size(word_size);
+}
+
+void ClassLoaderMetaspace::print_on(outputStream* out) const {
+  // Print both class virtual space counts and metaspace.
+  if (Verbose) {
+    vsm()->print_on(out);
+    if (Metaspace::using_class_space()) {
+      class_vsm()->print_on(out);
+    }
+  }
+}
+
+void ClassLoaderMetaspace::verify() {
   vsm()->verify();
-  if (using_class_space()) {
+  if (Metaspace::using_class_space()) {
     class_vsm()->verify();
   }
 }
 
-void Metaspace::dump(outputStream* const out) const {
+void ClassLoaderMetaspace::dump(outputStream* const out) const {
   out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, p2i(vsm()));
   vsm()->dump(out);
-  if (using_class_space()) {
+  if (Metaspace::using_class_space()) {
     out->print_cr("\nClass space manager: " INTPTR_FORMAT, p2i(class_vsm()));
     class_vsm()->dump(out);
   }
 }
 
+
+
 #ifdef ASSERT
 static void do_verify_chunk(Metachunk* chunk) {
   guarantee(chunk != NULL, "Sanity");
--- a/src/hotspot/share/memory/metaspace.hpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/src/hotspot/share/memory/metaspace.hpp	Thu Mar 15 07:15:39 2018 +0100
@@ -80,16 +80,11 @@
 // allocate() method returns a block for use as a
 // quantum of metadata.
 
-class Metaspace : public CHeapObj<mtClass> {
-  friend class VMStructs;
-  friend class SpaceManager;
-  friend class VM_CollectForMetadataAllocation;
-  friend class MetaspaceGC;
-  friend class MetaspaceUtils;
+// Namespace for important central static functions
+// (auxiliary stuff goes into MetaspaceUtils)
+class Metaspace : public AllStatic {
+
   friend class MetaspaceShared;
-  friend class CollectedHeap;
-  friend class PrintCLDMetaspaceInfoClosure;
-  friend class MetaspaceAllocationTest;
 
  public:
   enum MetadataType {
@@ -105,15 +100,6 @@
   };
 
  private:
-  static void verify_global_initialization();
-
-  void initialize(Mutex* lock, MetaspaceType type);
-
-  // Initialize the first chunk for a Metaspace.  Used for
-  // special cases such as the boot class loader, reflection
-  // class loader and anonymous class loader.
-  void initialize_first_chunk(MetaspaceType type, MetadataType mdtype);
-  Metachunk* get_initialization_chunk(MetaspaceType type, MetadataType mdtype);
 
   // Align up the word size to the allocation word size
   static size_t align_word_size_up(size_t);
@@ -136,23 +122,6 @@
   static size_t _reserve_alignment;
   DEBUG_ONLY(static bool   _frozen;)
 
-  SpaceManager* _vsm;
-  SpaceManager* vsm() const { return _vsm; }
-
-  SpaceManager* _class_vsm;
-  SpaceManager* class_vsm() const { return _class_vsm; }
-  SpaceManager* get_space_manager(MetadataType mdtype) {
-    assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
-    return mdtype == ClassType ? class_vsm() : vsm();
-  }
-
-  // Allocate space for metadata of type mdtype. This is space
-  // within a Metachunk and is used by
-  //   allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
-  MetaWord* allocate(size_t word_size, MetadataType mdtype);
-
-  MetaWord* expand_and_allocate(size_t size, MetadataType mdtype);
-
   // Virtual Space lists for both classes and other metadata
   static VirtualSpaceList* _space_list;
   static VirtualSpaceList* _class_space_list;
@@ -187,6 +156,9 @@
     assert(DumpSharedSpaces, "sanity");
     DEBUG_ONLY(_frozen = true;)
   }
+  static void assert_not_frozen() {
+    assert(!_frozen, "sanity");
+  }
 #ifdef _LP64
   static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
 #endif
@@ -201,17 +173,15 @@
 
   static void initialize_class_space(ReservedSpace rs);
 #endif
-  size_t class_chunk_size(size_t word_size);
 
  public:
 
-  Metaspace(Mutex* lock, MetaspaceType type);
-  ~Metaspace();
-
   static void ergo_initialize();
   static void global_initialize();
   static void post_initialize();
 
+  static void verify_global_initialization();
+
   static size_t first_chunk_word_size() { return _first_chunk_word_size; }
   static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; }
 
@@ -220,16 +190,6 @@
   static size_t commit_alignment()        { return _commit_alignment; }
   static size_t commit_alignment_words()  { return _commit_alignment / BytesPerWord; }
 
-  size_t used_words_slow(MetadataType mdtype) const;
-  size_t free_words_slow(MetadataType mdtype) const;
-  size_t capacity_words_slow(MetadataType mdtype) const;
-
-  size_t used_bytes_slow(MetadataType mdtype) const;
-  size_t capacity_bytes_slow(MetadataType mdtype) const;
-
-  size_t allocated_blocks_bytes() const;
-  size_t allocated_chunks_bytes() const;
-
   static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size,
                             MetaspaceObj::Type type, TRAPS);
   void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
@@ -237,8 +197,6 @@
   static bool contains(const void* ptr);
   static bool contains_non_shared(const void* ptr);
 
-  void dump(outputStream* const out) const;
-
   // Free empty virtualspaces
   static void purge(MetadataType mdtype);
   static void purge();
@@ -248,10 +206,6 @@
 
   static const char* metadata_type_name(Metaspace::MetadataType mdtype);
 
-  void print_on(outputStream* st) const;
-  // Debugging support
-  void verify();
-
   static void print_compressed_class_space(outputStream* st, const char* requested_addr = 0) NOT_LP64({});
 
   // Return TRUE only if UseCompressedClassPointers is True.
@@ -265,6 +219,69 @@
 
 };
 
+// Manages the metaspace portion belonging to a class loader
+class ClassLoaderMetaspace : public CHeapObj<mtClass> {
+  friend class CollectedHeap; // For expand_and_allocate()
+  friend class Metaspace;
+  friend class MetaspaceUtils;
+  friend class PrintCLDMetaspaceInfoClosure;
+  friend class VM_CollectForMetadataAllocation; // For expand_and_allocate()
+
+ private:
+
+  void initialize(Mutex* lock, Metaspace::MetaspaceType type);
+
+  // Initialize the first chunk for a Metaspace.  Used for
+  // special cases such as the boot class loader, reflection
+  // class loader and anonymous class loader.
+  void initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
+  Metachunk* get_initialization_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
+
+  SpaceManager* _vsm;
+  SpaceManager* vsm() const { return _vsm; }
+
+  SpaceManager* _class_vsm;
+  SpaceManager* class_vsm() const { return _class_vsm; }
+  SpaceManager* get_space_manager(Metaspace::MetadataType mdtype) {
+    assert(mdtype != Metaspace::MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
+    return mdtype == Metaspace::ClassType ? class_vsm() : vsm();
+  }
+
+  MetaWord* expand_and_allocate(size_t size, Metaspace::MetadataType mdtype);
+
+  size_t class_chunk_size(size_t word_size);
+
+ public:
+
+  ClassLoaderMetaspace(Mutex* lock, Metaspace::MetaspaceType type);
+  ~ClassLoaderMetaspace();
+
+  // Allocate space for metadata of type mdtype. This is space
+  // within a Metachunk and is used by
+  //   allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
+  MetaWord* allocate(size_t word_size, Metaspace::MetadataType mdtype);
+
+  size_t used_words_slow(Metaspace::MetadataType mdtype) const;
+  size_t free_words_slow(Metaspace::MetadataType mdtype) const;
+  size_t capacity_words_slow(Metaspace::MetadataType mdtype) const;
+
+  size_t used_bytes_slow(Metaspace::MetadataType mdtype) const;
+  size_t capacity_bytes_slow(Metaspace::MetadataType mdtype) const;
+
+  size_t allocated_blocks_bytes() const;
+  size_t allocated_chunks_bytes() const;
+
+  void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
+
+  void dump(outputStream* const out) const;
+
+  void print_on(outputStream* st) const;
+  // Debugging support
+  void verify();
+
+}; // ClassLoaderMetaspace
+
+
 class MetaspaceUtils : AllStatic {
   static size_t free_chunks_total_words(Metaspace::MetadataType mdtype);
 
--- a/test/hotspot/gtest/memory/test_metaspace_allocation.cpp	Wed Mar 14 21:36:41 2018 +0100
+++ b/test/hotspot/gtest/memory/test_metaspace_allocation.cpp	Thu Mar 15 07:15:39 2018 +0100
@@ -73,7 +73,7 @@
   struct {
     size_t allocated;
     Mutex* lock;
-    Metaspace* space;
+    ClassLoaderMetaspace* space;
     bool is_empty() const { return allocated == 0; }
     bool is_full() const { return allocated >= MAX_PER_METASPACE_ALLOCATION_WORDSIZE; }
   } _spaces[NUM_PARALLEL_METASPACES];
@@ -104,7 +104,7 @@
     // Let every ~10th space be an anonymous one to test different allocation patterns.
     const Metaspace::MetaspaceType msType = (os::random() % 100 < 10) ?
       Metaspace::AnonymousMetaspaceType : Metaspace::StandardMetaspaceType;
-    _spaces[i].space = new Metaspace(_spaces[i].lock, msType);
+    _spaces[i].space = new ClassLoaderMetaspace(_spaces[i].lock, msType);
     _spaces[i].allocated = 0;
     ASSERT_TRUE(_spaces[i].space != NULL);
   }