changeset 5626:bdfbb1fb19ca

8026391: The Metachunk header wastes memory Reviewed-by: coleenp, jmasa
author stefank
date Tue, 15 Oct 2013 14:28:51 +0200
parents f16726924734
children ec2e26e26183
files src/share/vm/memory/binaryTreeDictionary.cpp src/share/vm/memory/freeBlockDictionary.cpp src/share/vm/memory/freeList.cpp src/share/vm/memory/metablock.cpp src/share/vm/memory/metablock.hpp src/share/vm/memory/metachunk.cpp src/share/vm/memory/metachunk.hpp src/share/vm/memory/metaspace.cpp src/share/vm/memory/metaspace.hpp src/share/vm/prims/jni.cpp src/share/vm/runtime/vmStructs.cpp
diffstat 11 files changed, 232 insertions(+), 341 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/memory/binaryTreeDictionary.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/binaryTreeDictionary.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -28,7 +28,6 @@
 #include "memory/binaryTreeDictionary.hpp"
 #include "memory/freeList.hpp"
 #include "memory/freeBlockDictionary.hpp"
-#include "memory/metablock.hpp"
 #include "memory/metachunk.hpp"
 #include "runtime/globals.hpp"
 #include "utilities/ostream.hpp"
--- a/src/share/vm/memory/freeBlockDictionary.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/freeBlockDictionary.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -28,7 +28,6 @@
 #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
 #endif // INCLUDE_ALL_GCS
 #include "memory/freeBlockDictionary.hpp"
-#include "memory/metablock.hpp"
 #include "memory/metachunk.hpp"
 #include "runtime/thread.inline.hpp"
 #include "utilities/macros.hpp"
--- a/src/share/vm/memory/freeList.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/freeList.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "memory/freeBlockDictionary.hpp"
 #include "memory/freeList.hpp"
-#include "memory/metablock.hpp"
 #include "memory/metachunk.hpp"
 #include "memory/sharedHeap.hpp"
 #include "runtime/globals.hpp"
--- a/src/share/vm/memory/metablock.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "memory/allocation.hpp"
-#include "memory/metablock.hpp"
-#include "utilities/copy.hpp"
-#include "utilities/debug.hpp"
-
-// Blocks of space for metadata are allocated out of Metachunks.
-//
-// Metachunk are allocated out of MetadataVirtualspaces and once
-// allocated there is no explicit link between a Metachunk and
-// the MetadataVirtualspaces from which it was allocated.
-//
-// Each SpaceManager maintains a
-// list of the chunks it is using and the current chunk.  The current
-// chunk is the chunk from which allocations are done.  Space freed in
-// a chunk is placed on the free list of blocks (BlockFreelist) and
-// reused from there.
-//
-// Future modification
-//
-// The Metachunk can conceivable be replaced by the Chunk in
-// allocation.hpp.  Note that the latter Chunk is the space for
-// allocation (allocations from the chunk are out of the space in
-// the Chunk after the header for the Chunk) where as Metachunks
-// point to space in a VirtualSpace.  To replace Metachunks with
-// Chunks, change Chunks so that they can be allocated out of a VirtualSpace.
-size_t Metablock::_min_block_byte_size = sizeof(Metablock);
-
-// New blocks returned by the Metaspace are zero initialized.
-// We should fix the constructors to not assume this instead.
-Metablock* Metablock::initialize(MetaWord* p, size_t word_size) {
-  if (p == NULL) {
-    return NULL;
-  }
-
-  Metablock* result = (Metablock*) p;
-
-  // Clear the memory
-  Copy::fill_to_aligned_words((HeapWord*)result, word_size);
-#ifdef ASSERT
-  result->set_word_size(word_size);
-#endif
-  return result;
-}
--- a/src/share/vm/memory/metablock.hpp	Tue Oct 15 07:10:09 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-#ifndef SHARE_VM_MEMORY_METABLOCK_HPP
-#define SHARE_VM_MEMORY_METABLOCK_HPP
-
-// Metablock are the unit of allocation from a Chunk.  It is initialized
-// with the size of the requested allocation.  That size is overwritten
-// once the allocation returns.
-//
-// A Metablock may be reused by its SpaceManager but are never moved between
-// SpaceManagers.  There is no explicit link to the Metachunk
-// from which it was allocated.  Metablock may be deallocated and
-// put on a freelist but the space is never freed, rather
-// the Metachunk it is a part of will be deallocated when it's
-// associated class loader is collected.
-
-class Metablock VALUE_OBJ_CLASS_SPEC {
-  friend class VMStructs;
- private:
-  // Used to align the allocation (see below).
-  union block_t {
-    void* _data[3];
-    struct header_t {
-      size_t _word_size;
-      Metablock* _next;
-      Metablock* _prev;
-    } _header;
-  } _block;
-  static size_t _min_block_byte_size;
-
-  typedef union block_t Block;
-  typedef struct header_t Header;
-  const Block* block() const { return &_block; }
-  const Block::header_t* header() const { return &(block()->_header); }
- public:
-
-  static Metablock* initialize(MetaWord* p, size_t word_size);
-
-  // This places the body of the block at a 2 word boundary
-  // because every block starts on a 2 word boundary.  Work out
-  // how to make the body on a 2 word boundary if the block
-  // starts on a arbitrary boundary.  JJJ
-
-  size_t word_size() const  { return header()->_word_size; }
-  void set_word_size(size_t v) { _block._header._word_size = v; }
-  size_t size() const volatile { return _block._header._word_size; }
-  void set_size(size_t v) { _block._header._word_size = v; }
-  Metablock* next() const { return header()->_next; }
-  void set_next(Metablock* v) { _block._header._next = v; }
-  Metablock* prev() const { return header()->_prev; }
-  void set_prev(Metablock* v) { _block._header._prev = v; }
-
-  static size_t min_block_byte_size() { return _min_block_byte_size; }
-
-  bool is_free()                 { return header()->_word_size != 0; }
-  void clear_next()              { set_next(NULL); }
-  void link_prev(Metablock* ptr) { set_prev(ptr); }
-  uintptr_t* end()              { return ((uintptr_t*) this) + size(); }
-  bool cantCoalesce() const     { return false; }
-  void link_next(Metablock* ptr) { set_next(ptr); }
-  void link_after(Metablock* ptr){
-    link_next(ptr);
-    if (ptr != NULL) ptr->link_prev(this);
-  }
-
-  // Should not be needed in a free list of Metablocks
-  void markNotFree()            { ShouldNotReachHere(); }
-
-  // Debug support
-#ifdef ASSERT
-  void* prev_addr() const { return (void*)&_block._header._prev; }
-  void* next_addr() const { return (void*)&_block._header._next; }
-  void* size_addr() const { return (void*)&_block._header._word_size; }
-#endif
-  bool verify_chunk_in_free_list(Metablock* tc) const { return true; }
-  bool verify_par_locked() { return true; }
-
-  void assert_is_mangled() const {/* Don't check "\*/}
-};
-#endif // SHARE_VM_MEMORY_METABLOCK_HPP
--- a/src/share/vm/memory/metachunk.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/metachunk.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,42 +29,32 @@
 #include "utilities/debug.hpp"
 
 class VirtualSpaceNode;
-//
-// Future modification
-//
-// The Metachunk can conceivable be replaced by the Chunk in
-// allocation.hpp.  Note that the latter Chunk is the space for
-// allocation (allocations from the chunk are out of the space in
-// the Chunk after the header for the Chunk) where as Metachunks
-// point to space in a VirtualSpace.  To replace Metachunks with
-// Chunks, change Chunks so that they can be allocated out of a VirtualSpace.
 
 const size_t metadata_chunk_initialize = 0xf7f7f7f7;
 
-size_t Metachunk::_overhead =
-  Chunk::aligned_overhead_size(sizeof(Metachunk)) / BytesPerWord;
+size_t Metachunk::object_alignment() {
+  return ARENA_AMALLOC_ALIGNMENT;
+}
+
+size_t Metachunk::overhead() {
+  return align_size_up(sizeof(Metachunk), object_alignment()) / BytesPerWord;
+}
 
 // Metachunk methods
 
 Metachunk::Metachunk(size_t word_size,
-                     VirtualSpaceNode* container) :
-    _word_size(word_size),
-    _bottom(NULL),
-    _end(NULL),
+                     VirtualSpaceNode* container)
+    : Metabase<Metachunk>(word_size),
     _top(NULL),
-    _next(NULL),
-    _prev(NULL),
     _container(container)
 {
-  _bottom = (MetaWord*)this;
-  _top = (MetaWord*)this + _overhead;
-  _end = (MetaWord*)this + word_size;
+  _top = initial_top();
 #ifdef ASSERT
-  set_is_free(false);
+  set_is_tagged_free(false);
   size_t data_word_size = pointer_delta(end(),
-                                        top(),
+                                        _top,
                                         sizeof(MetaWord));
-  Copy::fill_to_words((HeapWord*) top(),
+  Copy::fill_to_words((HeapWord*)_top,
                       data_word_size,
                       metadata_chunk_initialize);
 #endif
@@ -82,22 +72,18 @@
 
 // _bottom points to the start of the chunk including the overhead.
 size_t Metachunk::used_word_size() const {
-  return pointer_delta(_top, _bottom, sizeof(MetaWord));
+  return pointer_delta(_top, bottom(), sizeof(MetaWord));
 }
 
 size_t Metachunk::free_word_size() const {
-  return pointer_delta(_end, _top, sizeof(MetaWord));
-}
-
-size_t Metachunk::capacity_word_size() const {
-  return pointer_delta(_end, _bottom, sizeof(MetaWord));
+  return pointer_delta(end(), _top, sizeof(MetaWord));
 }
 
 void Metachunk::print_on(outputStream* st) const {
   st->print_cr("Metachunk:"
                " bottom " PTR_FORMAT " top " PTR_FORMAT
                " end " PTR_FORMAT " size " SIZE_FORMAT,
-               bottom(), top(), end(), word_size());
+               bottom(), _top, end(), word_size());
   if (Verbose) {
     st->print_cr("    used " SIZE_FORMAT " free " SIZE_FORMAT,
                  used_word_size(), free_word_size());
@@ -109,8 +95,8 @@
   // Mangle the payload of the chunk and not the links that
   // maintain list of chunks.
   HeapWord* start = (HeapWord*)(bottom() + overhead());
-  size_t word_size = capacity_word_size() - overhead();
-  Copy::fill_to_words(start, word_size, metadata_chunk_initialize);
+  size_t size = word_size() - overhead();
+  Copy::fill_to_words(start, size, metadata_chunk_initialize);
 }
 #endif // PRODUCT
 
@@ -118,9 +104,68 @@
 #ifdef ASSERT
   // Cannot walk through the blocks unless the blocks have
   // headers with sizes.
-  assert(_bottom <= _top &&
-         _top <= _end,
+  assert(bottom() <= _top &&
+         _top <= (MetaWord*)end(),
          "Chunk has been smashed");
 #endif
   return;
 }
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+class TestMetachunk {
+ public:
+  static void test() {
+    size_t size = 2 * 1024 * 1024;
+    void* memory = malloc(size);
+    assert(memory != NULL, "Failed to malloc 2MB");
+
+    Metachunk* metachunk = ::new (memory) Metachunk(size / BytesPerWord, NULL);
+
+    assert(metachunk->bottom() == (MetaWord*)metachunk, "assert");
+    assert(metachunk->end() == (uintptr_t*)metachunk + metachunk->size(), "assert");
+
+    // Check sizes
+    assert(metachunk->size() == metachunk->word_size(), "assert");
+    assert(metachunk->word_size() == pointer_delta(metachunk->end(), metachunk->bottom(),
+        sizeof(MetaWord*)), "assert");
+
+    // Check usage
+    assert(metachunk->used_word_size() == metachunk->overhead(), "assert");
+    assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
+    assert(metachunk->top() == metachunk->initial_top(), "assert");
+    assert(metachunk->is_empty(), "assert");
+
+    // Allocate
+    size_t alloc_size = 64; // Words
+    assert(is_size_aligned(alloc_size, Metachunk::object_alignment()), "assert");
+
+    MetaWord* mem = metachunk->allocate(alloc_size);
+
+    // Check post alloc
+    assert(mem == metachunk->initial_top(), "assert");
+    assert(mem + alloc_size == metachunk->top(), "assert");
+    assert(metachunk->used_word_size() == metachunk->overhead() + alloc_size, "assert");
+    assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
+    assert(!metachunk->is_empty(), "assert");
+
+    // Clear chunk
+    metachunk->reset_empty();
+
+    // Check post clear
+    assert(metachunk->used_word_size() == metachunk->overhead(), "assert");
+    assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
+    assert(metachunk->top() == metachunk->initial_top(), "assert");
+    assert(metachunk->is_empty(), "assert");
+
+    free(memory);
+  }
+};
+
+void TestMetachunk_test() {
+  TestMetachunk::test();
+}
+
+#endif
--- a/src/share/vm/memory/metachunk.hpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/metachunk.hpp	Tue Oct 15 14:28:51 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,89 +24,44 @@
 #ifndef SHARE_VM_MEMORY_METACHUNK_HPP
 #define SHARE_VM_MEMORY_METACHUNK_HPP
 
-//  Metachunk - Quantum of allocation from a Virtualspace
-//    Metachunks are reused (when freed are put on a global freelist) and
-//    have no permanent association to a SpaceManager.
-
-//            +--------------+ <- end
-//            |              |          --+       ---+
-//            |              |            | free     |
-//            |              |            |          |
-//            |              |            |          | capacity
-//            |              |            |          |
-//            |              | <- top   --+          |
-//            |              |           ---+        |
-//            |              |              | used   |
-//            |              |              |        |
-//            |              |              |        |
-//            +--------------+ <- bottom ---+     ---+
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
 
 class VirtualSpaceNode;
 
-class Metachunk VALUE_OBJ_CLASS_SPEC {
-  // link to support lists of chunks
-  Metachunk* _next;
-  Metachunk* _prev;
-  VirtualSpaceNode* _container;
+// Super class of Metablock and Metachunk to allow them to
+// be put on the FreeList and in the BinaryTreeDictionary.
+template <class T>
+class Metabase VALUE_OBJ_CLASS_SPEC {
+  size_t _word_size;
+  T*     _next;
+  T*     _prev;
 
-  MetaWord* _bottom;
-  MetaWord* _end;
-  MetaWord* _top;
-  size_t _word_size;
-  // Used in a guarantee() so included in the Product builds
-  // even through it is only for debugging.
-  bool _is_free;
-
-  // Metachunks are allocated out of a MetadataVirtualSpace and
-  // and use some of its space to describe itself (plus alignment
-  // considerations).  Metadata is allocated in the rest of the chunk.
-  // This size is the overhead of maintaining the Metachunk within
-  // the space.
-  static size_t _overhead;
+ protected:
+  Metabase(size_t word_size) : _word_size(word_size), _next(NULL), _prev(NULL) {}
 
  public:
-  Metachunk(size_t word_size , VirtualSpaceNode* container);
+  T* next() const         { return _next; }
+  T* prev() const         { return _prev; }
+  void set_next(T* v)     { _next = v; assert(v != this, "Boom");}
+  void set_prev(T* v)     { _prev = v; assert(v != this, "Boom");}
+  void clear_next()       { set_next(NULL); }
+  void clear_prev()       { set_prev(NULL); }
 
-  // Used to add a Metachunk to a list of Metachunks
-  void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");}
-  void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");}
-  void set_container(VirtualSpaceNode* v) { _container = v; }
-
-  MetaWord* allocate(size_t word_size);
-
-  // Accessors
-  Metachunk* next() const { return _next; }
-  Metachunk* prev() const { return _prev; }
-  VirtualSpaceNode* container() const { return _container; }
-  MetaWord* bottom() const { return _bottom; }
-  MetaWord* end() const { return _end; }
-  MetaWord* top() const { return _top; }
-  size_t word_size() const { return _word_size; }
   size_t size() const volatile { return _word_size; }
   void set_size(size_t v) { _word_size = v; }
-  bool is_free() { return _is_free; }
-  void set_is_free(bool v) { _is_free = v; }
-  static size_t overhead() { return _overhead; }
-  void clear_next()              { set_next(NULL); }
-  void link_prev(Metachunk* ptr) { set_prev(ptr); }
-  uintptr_t* end()              { return ((uintptr_t*) this) + size(); }
-  bool cantCoalesce() const     { return false; }
-  void link_next(Metachunk* ptr) { set_next(ptr); }
-  void link_after(Metachunk* ptr){
+
+  void link_next(T* ptr)  { set_next(ptr); }
+  void link_prev(T* ptr)  { set_prev(ptr); }
+  void link_after(T* ptr) {
     link_next(ptr);
-    if (ptr != NULL) ptr->link_prev(this);
+    if (ptr != NULL) ptr->link_prev((T*)this);
   }
 
-  // Reset top to bottom so chunk can be reused.
-  void reset_empty() { _top = (_bottom + _overhead); _next = NULL; _prev = NULL; }
-  bool is_empty() { return _top == (_bottom + _overhead); }
+  uintptr_t* end() const        { return ((uintptr_t*) this) + size(); }
 
-  // used (has been allocated)
-  // free (available for future allocations)
-  // capacity (total size of chunk)
-  size_t used_word_size() const;
-  size_t free_word_size() const;
-  size_t capacity_word_size()const;
+  bool cantCoalesce() const     { return false; }
 
   // Debug support
 #ifdef ASSERT
@@ -114,14 +69,98 @@
   void* next_addr() const { return (void*)&_next; }
   void* size_addr() const { return (void*)&_word_size; }
 #endif
-  bool verify_chunk_in_free_list(Metachunk* tc) const { return true; }
+  bool verify_chunk_in_free_list(T* tc) const { return true; }
   bool verify_par_locked() { return true; }
 
   void assert_is_mangled() const {/* Don't check "\*/}
 
-  NOT_PRODUCT(void mangle();)
+  bool is_free()                 { return true; }
+};
+
+//  Metachunk - Quantum of allocation from a Virtualspace
+//    Metachunks are reused (when freed are put on a global freelist) and
+//    have no permanent association to a SpaceManager.
+
+//            +--------------+ <- end    --+       --+
+//            |              |             |         |
+//            |              |             | free    |
+//            |              |             |         |
+//            |              |             |         | size | capacity
+//            |              |             |         |
+//            |              | <- top   -- +         |
+//            |              |             |         |
+//            |              |             | used    |
+//            |              |             |         |
+//            |              |             |         |
+//            +--------------+ <- bottom --+       --+
+
+class Metachunk : public Metabase<Metachunk> {
+  friend class TestMetachunk;
+  // The VirtualSpaceNode containing this chunk.
+  VirtualSpaceNode* _container;
+
+  // Current allocation top.
+  MetaWord* _top;
+
+  DEBUG_ONLY(bool _is_tagged_free;)
+
+  MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
+  MetaWord* top() const         { return _top; }
+
+ public:
+  // Metachunks are allocated out of a MetadataVirtualSpace and
+  // and use some of its space to describe itself (plus alignment
+  // considerations).  Metadata is allocated in the rest of the chunk.
+  // This size is the overhead of maintaining the Metachunk within
+  // the space.
+
+  // Alignment of each allocation in the chunks.
+  static size_t object_alignment();
+
+  // Size of the Metachunk header, including alignment.
+  static size_t overhead();
+
+  Metachunk(size_t word_size , VirtualSpaceNode* container);
+
+  MetaWord* allocate(size_t word_size);
+
+  VirtualSpaceNode* container() const { return _container; }
+
+  MetaWord* bottom() const { return (MetaWord*) this; }
+
+  // Reset top to bottom so chunk can be reused.
+  void reset_empty() { _top = initial_top(); clear_next(); clear_prev(); }
+  bool is_empty() { return _top == initial_top(); }
+
+  // used (has been allocated)
+  // free (available for future allocations)
+  size_t word_size() const { return size(); }
+  size_t used_word_size() const;
+  size_t free_word_size() const;
+
+#ifdef ASSERT
+  void mangle();
+  bool is_tagged_free() { return _is_tagged_free; }
+  void set_is_tagged_free(bool v) { _is_tagged_free = v; }
+#endif
 
   void print_on(outputStream* st) const;
   void verify();
 };
+
+// Metablock is the unit of allocation from a Chunk.
+//
+// A Metablock may be reused by its SpaceManager but are never moved between
+// SpaceManagers.  There is no explicit link to the Metachunk
+// from which it was allocated.  Metablock may be deallocated and
+// put on a freelist but the space is never freed, rather
+// the Metachunk it is a part of will be deallocated when it's
+// associated class loader is collected.
+
+class Metablock : public Metabase<Metablock> {
+  friend class VMStructs;
+ public:
+  Metablock(size_t word_size) : Metabase<Metablock>(word_size) {}
+};
+
 #endif  // SHARE_VM_MEMORY_METACHUNK_HPP
--- a/src/share/vm/memory/metaspace.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/metaspace.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -30,7 +30,6 @@
 #include "memory/filemap.hpp"
 #include "memory/freeList.hpp"
 #include "memory/gcLocker.hpp"
-#include "memory/metablock.hpp"
 #include "memory/metachunk.hpp"
 #include "memory/metaspace.hpp"
 #include "memory/metaspaceShared.hpp"
@@ -49,8 +48,8 @@
 
 typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
 typedef BinaryTreeDictionary<Metachunk, FreeList> ChunkTreeDictionary;
-// Define this macro to enable slow integrity checking of
-// the free chunk lists
+
+// Set this constant to enable slow integrity checking of the free chunk lists
 const bool metaspace_slow_verify = false;
 
 // Parameters for stress mode testing
@@ -92,24 +91,9 @@
 uint MetaspaceGC::_shrink_factor = 0;
 bool MetaspaceGC::_should_concurrent_collect = false;
 
-// Blocks of space for metadata are allocated out of Metachunks.
-//
-// Metachunk are allocated out of MetadataVirtualspaces and once
-// allocated there is no explicit link between a Metachunk and
-// the MetadataVirtualspaces from which it was allocated.
-//
-// Each SpaceManager maintains a
-// list of the chunks it is using and the current chunk.  The current
-// chunk is the chunk from which allocations are done.  Space freed in
-// a chunk is placed on the free list of blocks (BlockFreelist) and
-// reused from there.
-
 typedef class FreeList<Metachunk> ChunkList;
 
 // Manages the global free lists of chunks.
-// Has three lists of free chunks, and a total size and
-// count that includes all three
-
 class ChunkManager : public CHeapObj<mtInternal> {
 
   // Free list of chunks of different sizes.
@@ -119,7 +103,6 @@
   //   HumongousChunk
   ChunkList _free_chunks[NumberOfFreeLists];
 
-
   //   HumongousChunk
   ChunkTreeDictionary _humongous_dictionary;
 
@@ -230,7 +213,6 @@
 // to the allocation of a quantum of metadata).
 class BlockFreelist VALUE_OBJ_CLASS_SPEC {
   BlockTreeDictionary* _dictionary;
-  static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size);
 
   // Only allocate and split from freelist if the size of the allocation
   // is at least 1/4th the size of the available block.
@@ -258,6 +240,7 @@
   void print_on(outputStream* st) const;
 };
 
+// A VirtualSpaceList node.
 class VirtualSpaceNode : public CHeapObj<mtClass> {
   friend class VirtualSpaceList;
 
@@ -414,13 +397,13 @@
   Metachunk* chunk = first_chunk();
   Metachunk* invalid_chunk = (Metachunk*) top();
   while (chunk < invalid_chunk ) {
-    assert(chunk->is_free(), "Should be marked free");
-      MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
-      chunk_manager->remove_chunk(chunk);
-      assert(chunk->next() == NULL &&
-             chunk->prev() == NULL,
-             "Was not removed from its list");
-      chunk = (Metachunk*) next;
+    assert(chunk->is_tagged_free(), "Should be tagged free");
+    MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+    chunk_manager->remove_chunk(chunk);
+    assert(chunk->next() == NULL &&
+           chunk->prev() == NULL,
+           "Was not removed from its list");
+    chunk = (Metachunk*) next;
   }
 }
 
@@ -434,7 +417,7 @@
     // Don't count the chunks on the free lists.  Those are
     // still part of the VirtualSpaceNode but not currently
     // counted.
-    if (!chunk->is_free()) {
+    if (!chunk->is_tagged_free()) {
       count++;
     }
     chunk = (Metachunk*) next;
@@ -753,14 +736,11 @@
 #endif
 
   size_t get_raw_word_size(size_t word_size) {
-    // If only the dictionary is going to be used (i.e., no
-    // indexed free list), then there is a minimum size requirement.
-    // MinChunkSize is a placeholder for the real minimum size JJJ
     size_t byte_size = word_size * BytesPerWord;
 
-    size_t raw_bytes_size = MAX2(byte_size,
-                                 Metablock::min_block_byte_size());
-    raw_bytes_size = ARENA_ALIGN(raw_bytes_size);
+    size_t raw_bytes_size = MAX2(byte_size, sizeof(Metablock));
+    raw_bytes_size = align_size_up(raw_bytes_size, Metachunk::object_alignment());
+
     size_t raw_word_size = raw_bytes_size / BytesPerWord;
     assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem");
 
@@ -813,17 +793,8 @@
   }
 }
 
-Metablock* BlockFreelist::initialize_free_chunk(MetaWord* p, size_t word_size) {
-  Metablock* block = (Metablock*) p;
-  block->set_word_size(word_size);
-  block->set_prev(NULL);
-  block->set_next(NULL);
-
-  return block;
-}
-
 void BlockFreelist::return_block(MetaWord* p, size_t word_size) {
-  Metablock* free_chunk = initialize_free_chunk(p, word_size);
+  Metablock* free_chunk = ::new (p) Metablock(word_size);
   if (dictionary() == NULL) {
    _dictionary = new BlockTreeDictionary();
   }
@@ -1069,7 +1040,7 @@
   }
 
   // Chunk is being removed from the chunks free list.
-  dec_free_chunks_total(chunk->capacity_word_size());
+  dec_free_chunks_total(chunk->word_size());
 }
 
 // Walk the list of VirtualSpaceNodes and delete
@@ -1760,7 +1731,7 @@
   chunk->set_next(free_list->head());
   free_list->set_head(chunk);
   // chunk is being returned to the chunk free list
-  inc_free_chunks_total(chunk->capacity_word_size());
+  inc_free_chunks_total(chunk->word_size());
   slow_locked_verify();
 }
 
@@ -1822,7 +1793,7 @@
   }
 
   // Chunk is being removed from the chunks free list.
-  dec_free_chunks_total(chunk->capacity_word_size());
+  dec_free_chunks_total(chunk->word_size());
 
   // Remove it from the links to this freelist
   chunk->set_next(NULL);
@@ -1830,7 +1801,7 @@
 #ifdef ASSERT
   // Chunk is no longer on any freelist. Setting to false make container_count_slow()
   // work.
-  chunk->set_is_free(false);
+  chunk->set_is_tagged_free(false);
 #endif
   chunk->container()->inc_container_count();
 
@@ -1962,7 +1933,7 @@
     for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
       Metachunk* chunk = chunks_in_use(i);
       while (chunk != NULL) {
-        sum += chunk->capacity_word_size();
+        sum += chunk->word_size();
         chunk = chunk->next();
       }
     }
@@ -2210,7 +2181,7 @@
     // Capture the next link before it is changed
     // by the call to return_chunk_at_head();
     Metachunk* next = cur->next();
-    cur->set_is_free(true);
+    DEBUG_ONLY(cur->set_is_tagged_free(true);)
     list->return_chunk_at_head(cur);
     cur = next;
   }
@@ -2282,7 +2253,7 @@
 
   while (humongous_chunks != NULL) {
 #ifdef ASSERT
-    humongous_chunks->set_is_free(true);
+    humongous_chunks->set_is_tagged_free(true);
 #endif
     if (TraceMetadataChunkAllocation && Verbose) {
       gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
@@ -2545,7 +2516,7 @@
       curr->print_on(out);
       curr_total += curr->word_size();
       used += curr->used_word_size();
-      capacity += curr->capacity_word_size();
+      capacity += curr->word_size();
       waste += curr->free_word_size() + curr->overhead();;
     }
   }
@@ -3396,7 +3367,7 @@
 }
 
 
-Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
+MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
                               bool read_only, MetaspaceObj::Type type, TRAPS) {
   if (HAS_PENDING_EXCEPTION) {
     assert(false, "Should not allocate with exception pending");
@@ -3415,10 +3386,14 @@
     MetaWord* result = space->allocate(word_size, NonClassType);
     if (result == NULL) {
       report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite);
-    } else {
-      space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size));
     }
-    return Metablock::initialize(result, word_size);
+
+    space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size));
+
+    // Zero initialize.
+    Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
+
+    return result;
   }
 
   MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;
@@ -3443,7 +3418,10 @@
     return NULL;
   }
 
-  return Metablock::initialize(result, word_size);
+  // Zero initialize.
+  Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
+
+  return result;
 }
 
 void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) {
--- a/src/share/vm/memory/metaspace.hpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/memory/metaspace.hpp	Tue Oct 15 14:28:51 2013 +0200
@@ -139,7 +139,6 @@
   // Allocate space for metadata of type mdtype. This is space
   // within a Metachunk and is used by
   //   allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
-  // which returns a Metablock.
   MetaWord* allocate(size_t word_size, MetadataType mdtype);
 
   // Virtual Space lists for both classes and other metadata
@@ -217,8 +216,8 @@
   size_t used_bytes_slow(MetadataType mdtype) const;
   size_t capacity_bytes_slow(MetadataType mdtype) const;
 
-  static Metablock* allocate(ClassLoaderData* loader_data, size_t word_size,
-                             bool read_only, MetaspaceObj::Type type, TRAPS);
+  static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size,
+                            bool read_only, MetaspaceObj::Type type, TRAPS);
   void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
 
   MetaWord* expand_and_allocate(size_t size,
--- a/src/share/vm/prims/jni.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/prims/jni.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -5059,6 +5059,7 @@
 void TestReserveMemorySpecial_test();
 void TestVirtualSpace_test();
 void TestMetaspaceAux_test();
+void TestMetachunk_test();
 #if INCLUDE_ALL_GCS
 void TestG1BiasedArray_test();
 #endif
@@ -5070,6 +5071,7 @@
     run_unit_test(TestReserveMemorySpecial_test());
     run_unit_test(TestVirtualSpace_test());
     run_unit_test(TestMetaspaceAux_test());
+    run_unit_test(TestMetachunk_test());
     run_unit_test(GlobalDefinitions::test_globals());
     run_unit_test(GCTimerAllTest::all());
     run_unit_test(arrayOopDesc::test_max_array_length());
--- a/src/share/vm/runtime/vmStructs.cpp	Tue Oct 15 07:10:09 2013 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Tue Oct 15 14:28:51 2013 +0200
@@ -58,7 +58,7 @@
 #include "memory/generation.hpp"
 #include "memory/generationSpec.hpp"
 #include "memory/heap.hpp"
-#include "memory/metablock.hpp"
+#include "memory/metachunk.hpp"
 #include "memory/referenceType.hpp"
 #include "memory/space.hpp"
 #include "memory/tenuredGeneration.hpp"