提交 0d459bfa 编写于 作者: J jmasa

8005082: NPG: Add specialized Metachunk sizes for reflection and anonymous classloaders

Reviewed-by: johnc, coleenp
上级 73ee7ee2
...@@ -330,10 +330,19 @@ Metaspace* ClassLoaderData::metaspace_non_null() { ...@@ -330,10 +330,19 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
} }
if (this == the_null_class_loader_data()) { if (this == the_null_class_loader_data()) {
assert (class_loader() == NULL, "Must be"); assert (class_loader() == NULL, "Must be");
size_t word_size = Metaspace::first_chunk_word_size(); set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
set_metaspace(new Metaspace(_metaspace_lock, word_size)); } else if (is_anonymous()) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
} else { } else {
set_metaspace(new Metaspace(_metaspace_lock)); // default size for now. set_metaspace(new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType));
} }
} }
return _metaspace; return _metaspace;
...@@ -672,8 +681,8 @@ void ClassLoaderData::initialize_shared_metaspaces() { ...@@ -672,8 +681,8 @@ void ClassLoaderData::initialize_shared_metaspaces() {
"only supported for null loader data for now"); "only supported for null loader data for now");
assert (!_shared_metaspaces_initialized, "only initialize once"); assert (!_shared_metaspaces_initialized, "only initialize once");
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
_ro_metaspace = new Metaspace(_metaspace_lock, SharedReadOnlySize/wordSize); _ro_metaspace = new Metaspace(_metaspace_lock, Metaspace::ROMetaspaceType);
_rw_metaspace = new Metaspace(_metaspace_lock, SharedReadWriteSize/wordSize); _rw_metaspace = new Metaspace(_metaspace_lock, Metaspace::ReadWriteMetaspaceType);
_shared_metaspaces_initialized = true; _shared_metaspaces_initialized = true;
} }
......
...@@ -67,7 +67,8 @@ void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const { ...@@ -67,7 +67,8 @@ void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
} }
template <class Chunk_t, template <class> class FreeList_t> template <class Chunk_t, template <class> class FreeList_t>
TreeList<Chunk_t, FreeList_t>::TreeList() {} TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
_left(NULL), _right(NULL) {}
template <class Chunk_t, template <class> class FreeList_t> template <class Chunk_t, template <class> class FreeList_t>
TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>*
...@@ -82,7 +83,7 @@ TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) { ...@@ -82,7 +83,7 @@ TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
tl->link_head(tc); tl->link_head(tc);
tl->link_tail(tc); tl->link_tail(tc);
tl->set_count(1); tl->set_count(1);
assert(tl->parent() == NULL, "Should be clear");
return tl; return tl;
} }
......
...@@ -777,6 +777,15 @@ MetaWord* CollectorPolicy::satisfy_failed_metadata_allocation( ...@@ -777,6 +777,15 @@ MetaWord* CollectorPolicy::satisfy_failed_metadata_allocation(
full_gc_count, full_gc_count,
GCCause::_metadata_GC_threshold); GCCause::_metadata_GC_threshold);
VMThread::execute(&op); VMThread::execute(&op);
// If GC was locked out, try again. Check
// before checking success because the prologue
// could have succeeded and the GC still have
// been locked out.
if (op.gc_locked()) {
continue;
}
if (op.prologue_succeeded()) { if (op.prologue_succeeded()) {
return op.result(); return op.result();
} }
......
...@@ -56,6 +56,7 @@ Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) { ...@@ -56,6 +56,7 @@ Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) {
assert(chunk_end > chunk_bottom, "Chunk must be too small"); assert(chunk_end > chunk_bottom, "Chunk must be too small");
chunk->set_end(chunk_end); chunk->set_end(chunk_end);
chunk->set_next(NULL); chunk->set_next(NULL);
chunk->set_prev(NULL);
chunk->set_word_size(word_size); chunk->set_word_size(word_size);
#ifdef ASSERT #ifdef ASSERT
size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord)); size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord));
...@@ -76,15 +77,15 @@ MetaWord* Metachunk::allocate(size_t word_size) { ...@@ -76,15 +77,15 @@ MetaWord* Metachunk::allocate(size_t word_size) {
} }
// _bottom points to the start of the chunk including the overhead. // _bottom points to the start of the chunk including the overhead.
size_t Metachunk::used_word_size() { 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() { size_t Metachunk::free_word_size() const {
return pointer_delta(_end, _top, sizeof(MetaWord)); return pointer_delta(_end, _top, sizeof(MetaWord));
} }
size_t Metachunk::capacity_word_size() { size_t Metachunk::capacity_word_size() const {
return pointer_delta(_end, _bottom, sizeof(MetaWord)); return pointer_delta(_end, _bottom, sizeof(MetaWord));
} }
...@@ -93,6 +94,10 @@ void Metachunk::print_on(outputStream* st) const { ...@@ -93,6 +94,10 @@ void Metachunk::print_on(outputStream* st) const {
" bottom " PTR_FORMAT " top " PTR_FORMAT " bottom " PTR_FORMAT " top " PTR_FORMAT
" end " PTR_FORMAT " size " SIZE_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());
}
} }
#ifndef PRODUCT #ifndef PRODUCT
......
...@@ -67,9 +67,11 @@ class Metachunk VALUE_OBJ_CLASS_SPEC { ...@@ -67,9 +67,11 @@ class Metachunk VALUE_OBJ_CLASS_SPEC {
void set_word_size(size_t v) { _word_size = v; } void set_word_size(size_t v) { _word_size = v; }
public: public:
#ifdef ASSERT #ifdef ASSERT
Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false) {} Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false),
_next(NULL), _prev(NULL) {}
#else #else
Metachunk() : _bottom(NULL), _end(NULL), _top(NULL) {} Metachunk() : _bottom(NULL), _end(NULL), _top(NULL),
_next(NULL), _prev(NULL) {}
#endif #endif
// Used to add a Metachunk to a list of Metachunks // Used to add a Metachunk to a list of Metachunks
...@@ -102,15 +104,15 @@ class Metachunk VALUE_OBJ_CLASS_SPEC { ...@@ -102,15 +104,15 @@ class Metachunk VALUE_OBJ_CLASS_SPEC {
} }
// Reset top to bottom so chunk can be reused. // Reset top to bottom so chunk can be reused.
void reset_empty() { _top = (_bottom + _overhead); } void reset_empty() { _top = (_bottom + _overhead); _next = NULL; _prev = NULL; }
bool is_empty() { return _top == (_bottom + _overhead); } bool is_empty() { return _top == (_bottom + _overhead); }
// used (has been allocated) // used (has been allocated)
// free (available for future allocations) // free (available for future allocations)
// capacity (total size of chunk) // capacity (total size of chunk)
size_t used_word_size(); size_t used_word_size() const;
size_t free_word_size(); size_t free_word_size() const;
size_t capacity_word_size(); size_t capacity_word_size()const;
// Debug support // Debug support
#ifdef ASSERT #ifdef ASSERT
......
...@@ -58,11 +58,23 @@ MetaWord* last_allocated = 0; ...@@ -58,11 +58,23 @@ MetaWord* last_allocated = 0;
// Used in declarations in SpaceManager and ChunkManager // Used in declarations in SpaceManager and ChunkManager
enum ChunkIndex { enum ChunkIndex {
SmallIndex = 0, ZeroIndex = 0,
MediumIndex = 1, SpecializedIndex = ZeroIndex,
HumongousIndex = 2, SmallIndex = SpecializedIndex + 1,
NumberOfFreeLists = 2, MediumIndex = SmallIndex + 1,
NumberOfInUseLists = 3 HumongousIndex = MediumIndex + 1,
NumberOfFreeLists = 3,
NumberOfInUseLists = 4
};
enum ChunkSizes { // in words.
ClassSpecializedChunk = 128,
SpecializedChunk = 128,
ClassSmallChunk = 256,
SmallChunk = 512,
ClassMediumChunk = 1 * K,
MediumChunk = 8 * K,
HumongousChunkGranularity = 8
}; };
static ChunkIndex next_chunk_index(ChunkIndex i) { static ChunkIndex next_chunk_index(ChunkIndex i) {
...@@ -126,6 +138,7 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC { ...@@ -126,6 +138,7 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC {
// HumongousChunk // HumongousChunk
ChunkList _free_chunks[NumberOfFreeLists]; ChunkList _free_chunks[NumberOfFreeLists];
// HumongousChunk // HumongousChunk
ChunkTreeDictionary _humongous_dictionary; ChunkTreeDictionary _humongous_dictionary;
...@@ -169,6 +182,10 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC { ...@@ -169,6 +182,10 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC {
Metachunk* chunk_freelist_allocate(size_t word_size); Metachunk* chunk_freelist_allocate(size_t word_size);
void chunk_freelist_deallocate(Metachunk* chunk); void chunk_freelist_deallocate(Metachunk* chunk);
// Map a size to a list index assuming that there are lists
// for special, small, medium, and humongous chunks.
static ChunkIndex list_index(size_t size);
// Total of the space in the free chunks list // Total of the space in the free chunks list
size_t free_chunks_total(); size_t free_chunks_total();
size_t free_chunks_total_in_bytes(); size_t free_chunks_total_in_bytes();
...@@ -180,8 +197,6 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC { ...@@ -180,8 +197,6 @@ class ChunkManager VALUE_OBJ_CLASS_SPEC {
Atomic::add_ptr(count, &_free_chunks_count); Atomic::add_ptr(count, &_free_chunks_count);
Atomic::add_ptr(v, &_free_chunks_total); Atomic::add_ptr(v, &_free_chunks_total);
} }
ChunkList* free_medium_chunks() { return &_free_chunks[1]; }
ChunkList* free_small_chunks() { return &_free_chunks[0]; }
ChunkTreeDictionary* humongous_dictionary() { ChunkTreeDictionary* humongous_dictionary() {
return &_humongous_dictionary; return &_humongous_dictionary;
} }
...@@ -400,7 +415,14 @@ class VirtualSpaceList : public CHeapObj<mtClass> { ...@@ -400,7 +415,14 @@ class VirtualSpaceList : public CHeapObj<mtClass> {
VirtualSpaceList(size_t word_size); VirtualSpaceList(size_t word_size);
VirtualSpaceList(ReservedSpace rs); VirtualSpaceList(ReservedSpace rs);
Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words); Metachunk* get_new_chunk(size_t word_size,
size_t grow_chunks_by_words,
size_t medium_chunk_bunch);
// Get the first chunk for a Metaspace. Used for
// special cases such as the boot class loader, reflection
// class loader and anonymous class loader.
Metachunk* get_initialization_chunk(size_t word_size, size_t chunk_bunch);
VirtualSpaceNode* current_virtual_space() { VirtualSpaceNode* current_virtual_space() {
return _current_virtual_space; return _current_virtual_space;
...@@ -501,9 +523,13 @@ class SpaceManager : public CHeapObj<mtClass> { ...@@ -501,9 +523,13 @@ class SpaceManager : public CHeapObj<mtClass> {
friend class Metadebug; friend class Metadebug;
private: private:
// protects allocations and contains. // protects allocations and contains.
Mutex* const _lock; Mutex* const _lock;
// Chunk related size
size_t _medium_chunk_bunch;
// List of chunks in use by this SpaceManager. Allocations // List of chunks in use by this SpaceManager. Allocations
// are done from the current chunk. The list is used for deallocating // are done from the current chunk. The list is used for deallocating
// chunks when the SpaceManager is freed. // chunks when the SpaceManager is freed.
...@@ -532,6 +558,7 @@ class SpaceManager : public CHeapObj<mtClass> { ...@@ -532,6 +558,7 @@ class SpaceManager : public CHeapObj<mtClass> {
static const int _expand_lock_rank; static const int _expand_lock_rank;
static Mutex* const _expand_lock; static Mutex* const _expand_lock;
private:
// Accessors // Accessors
Metachunk* chunks_in_use(ChunkIndex index) const { return _chunks_in_use[index]; } Metachunk* chunks_in_use(ChunkIndex index) const { return _chunks_in_use[index]; }
void set_chunks_in_use(ChunkIndex index, Metachunk* v) { _chunks_in_use[index] = v; } void set_chunks_in_use(ChunkIndex index, Metachunk* v) { _chunks_in_use[index] = v; }
...@@ -554,23 +581,37 @@ class SpaceManager : public CHeapObj<mtClass> { ...@@ -554,23 +581,37 @@ class SpaceManager : public CHeapObj<mtClass> {
Mutex* lock() const { return _lock; } Mutex* lock() const { return _lock; }
const char* chunk_size_name(ChunkIndex index) const;
protected:
void initialize();
public: public:
SpaceManager(Mutex* lock, VirtualSpaceList* vs_list); SpaceManager(Mutex* lock,
VirtualSpaceList* vs_list);
~SpaceManager(); ~SpaceManager();
enum ChunkSizes { // in words. enum ChunkMultiples {
SmallChunk = 512, MediumChunkMultiple = 4
MediumChunk = 8 * K,
MediumChunkBunch = 4 * MediumChunk
}; };
// Accessors // Accessors
size_t specialized_chunk_size() { return SpecializedChunk; }
size_t small_chunk_size() { return (size_t) vs_list()->is_class() ? ClassSmallChunk : SmallChunk; }
size_t medium_chunk_size() { return (size_t) vs_list()->is_class() ? ClassMediumChunk : MediumChunk; }
size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
size_t allocation_total() const { return _allocation_total; } size_t allocation_total() const { return _allocation_total; }
void inc_allocation_total(size_t v) { Atomic::add_ptr(v, &_allocation_total); } void inc_allocation_total(size_t v) { Atomic::add_ptr(v, &_allocation_total); }
static bool is_humongous(size_t word_size) { return word_size > MediumChunk; } bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); }
static Mutex* expand_lock() { return _expand_lock; } static Mutex* expand_lock() { return _expand_lock; }
// Set the sizes for the initial chunks.
void get_initial_chunk_sizes(Metaspace::MetaspaceType type,
size_t* chunk_word_size,
size_t* class_chunk_word_size);
size_t sum_capacity_in_chunks_in_use() const; size_t sum_capacity_in_chunks_in_use() const;
size_t sum_used_in_chunks_in_use() const; size_t sum_used_in_chunks_in_use() const;
size_t sum_free_in_chunks_in_use() const; size_t sum_free_in_chunks_in_use() const;
...@@ -580,6 +621,8 @@ class SpaceManager : public CHeapObj<mtClass> { ...@@ -580,6 +621,8 @@ class SpaceManager : public CHeapObj<mtClass> {
size_t sum_count_in_chunks_in_use(); size_t sum_count_in_chunks_in_use();
size_t sum_count_in_chunks_in_use(ChunkIndex i); size_t sum_count_in_chunks_in_use(ChunkIndex i);
Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words);
// Block allocation and deallocation. // Block allocation and deallocation.
// Allocates a block from the current chunk // Allocates a block from the current chunk
MetaWord* allocate(size_t word_size); MetaWord* allocate(size_t word_size);
...@@ -772,8 +815,10 @@ bool VirtualSpaceNode::initialize() { ...@@ -772,8 +815,10 @@ bool VirtualSpaceNode::initialize() {
return false; return false;
} }
// Commit only 1 page instead of the whole reserved space _rs.size() // An allocation out of this Virtualspace that is larger
size_t committed_byte_size = os::vm_page_size(); // than an initial commit size can waste that initial committed
// space.
size_t committed_byte_size = 0;
bool result = virtual_space()->initialize(_rs, committed_byte_size); bool result = virtual_space()->initialize(_rs, committed_byte_size);
if (result) { if (result) {
set_top((MetaWord*)virtual_space()->low()); set_top((MetaWord*)virtual_space()->low());
...@@ -799,7 +844,8 @@ void VirtualSpaceNode::print_on(outputStream* st) const { ...@@ -799,7 +844,8 @@ void VirtualSpaceNode::print_on(outputStream* st) const {
st->print_cr(" space @ " PTR_FORMAT " " SIZE_FORMAT "K, %3d%% used " st->print_cr(" space @ " PTR_FORMAT " " SIZE_FORMAT "K, %3d%% used "
"[" PTR_FORMAT ", " PTR_FORMAT ", " "[" PTR_FORMAT ", " PTR_FORMAT ", "
PTR_FORMAT ", " PTR_FORMAT ")", PTR_FORMAT ", " PTR_FORMAT ")",
vs, capacity / K, used * 100 / capacity, vs, capacity / K,
capacity == 0 ? 0 : used * 100 / capacity,
bottom(), top(), end(), bottom(), top(), end(),
vs->high_boundary()); vs->high_boundary());
} }
...@@ -922,7 +968,8 @@ void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry, size_t vs_word_size) ...@@ -922,7 +968,8 @@ void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry, size_t vs_word_size)
} }
Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
size_t grow_chunks_by_words) { size_t grow_chunks_by_words,
size_t medium_chunk_bunch) {
// Get a chunk from the chunk freelist // Get a chunk from the chunk freelist
Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
...@@ -935,8 +982,8 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, ...@@ -935,8 +982,8 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
if (next == NULL) { if (next == NULL) {
// Not enough room in current virtual space. Try to commit // Not enough room in current virtual space. Try to commit
// more space. // more space.
size_t expand_vs_by_words = MAX2((size_t)SpaceManager::MediumChunkBunch, size_t expand_vs_by_words = MAX2(medium_chunk_bunch,
grow_chunks_by_words); grow_chunks_by_words);
size_t page_size_words = os::vm_page_size() / BytesPerWord; size_t page_size_words = os::vm_page_size() / BytesPerWord;
size_t aligned_expand_vs_by_words = align_size_up(expand_vs_by_words, size_t aligned_expand_vs_by_words = align_size_up(expand_vs_by_words,
page_size_words); page_size_words);
...@@ -954,12 +1001,6 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, ...@@ -954,12 +1001,6 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
// Got it. It's on the list now. Get a chunk from it. // Got it. It's on the list now. Get a chunk from it.
next = current_virtual_space()->get_chunk_vs_with_expand(grow_chunks_by_words); next = current_virtual_space()->get_chunk_vs_with_expand(grow_chunks_by_words);
} }
if (TraceMetadataHumongousAllocation && SpaceManager::is_humongous(word_size)) {
gclog_or_tty->print_cr(" aligned_expand_vs_by_words " PTR_FORMAT,
aligned_expand_vs_by_words);
gclog_or_tty->print_cr(" grow_vs_words " PTR_FORMAT,
grow_vs_words);
}
} else { } else {
// Allocation will fail and induce a GC // Allocation will fail and induce a GC
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
...@@ -974,9 +1015,20 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, ...@@ -974,9 +1015,20 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
} }
} }
assert(next == NULL || (next->next() == NULL && next->prev() == NULL),
"New chunk is still on some list");
return next; return next;
} }
Metachunk* VirtualSpaceList::get_initialization_chunk(size_t chunk_word_size,
size_t chunk_bunch) {
// Get a chunk from the chunk freelist
Metachunk* new_chunk = get_new_chunk(chunk_word_size,
chunk_word_size,
chunk_bunch);
return new_chunk;
}
void VirtualSpaceList::print_on(outputStream* st) const { void VirtualSpaceList::print_on(outputStream* st) const {
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
VirtualSpaceListIterator iter(virtual_space_list()); VirtualSpaceListIterator iter(virtual_space_list());
...@@ -1373,16 +1425,17 @@ size_t ChunkList::sum_list_capacity() { ...@@ -1373,16 +1425,17 @@ size_t ChunkList::sum_list_capacity() {
void ChunkList::add_at_head(Metachunk* head, Metachunk* tail) { void ChunkList::add_at_head(Metachunk* head, Metachunk* tail) {
assert_lock_strong(SpaceManager::expand_lock()); assert_lock_strong(SpaceManager::expand_lock());
assert(tail->next() == NULL, "Not the tail"); assert(head == tail || tail->next() == NULL,
"Not the tail or the head has already been added to a list");
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
tty->print("ChunkList::add_at_head: "); gclog_or_tty->print("ChunkList::add_at_head(head, tail): ");
Metachunk* cur = head; Metachunk* cur = head;
while (cur != NULL) { while (cur != NULL) {
tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", cur, cur->word_size()); gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", cur, cur->word_size());
cur = cur->next(); cur = cur->next();
} }
tty->print_cr(""); gclog_or_tty->print_cr("");
} }
if (tail != NULL) { if (tail != NULL) {
...@@ -1486,13 +1539,13 @@ void ChunkManager::locked_verify() { ...@@ -1486,13 +1539,13 @@ void ChunkManager::locked_verify() {
void ChunkManager::locked_print_free_chunks(outputStream* st) { void ChunkManager::locked_print_free_chunks(outputStream* st) {
assert_lock_strong(SpaceManager::expand_lock()); assert_lock_strong(SpaceManager::expand_lock());
st->print_cr("Free chunk total 0x%x count 0x%x", st->print_cr("Free chunk total " SIZE_FORMAT " count " SIZE_FORMAT,
_free_chunks_total, _free_chunks_count); _free_chunks_total, _free_chunks_count);
} }
void ChunkManager::locked_print_sum_free_chunks(outputStream* st) { void ChunkManager::locked_print_sum_free_chunks(outputStream* st) {
assert_lock_strong(SpaceManager::expand_lock()); assert_lock_strong(SpaceManager::expand_lock());
st->print_cr("Sum free chunk total 0x%x count 0x%x", st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT,
sum_free_chunks(), sum_free_chunks_count()); sum_free_chunks(), sum_free_chunks_count());
} }
ChunkList* ChunkManager::free_chunks(ChunkIndex index) { ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
...@@ -1504,7 +1557,7 @@ ChunkList* ChunkManager::free_chunks(ChunkIndex index) { ...@@ -1504,7 +1557,7 @@ ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
size_t ChunkManager::sum_free_chunks() { size_t ChunkManager::sum_free_chunks() {
assert_lock_strong(SpaceManager::expand_lock()); assert_lock_strong(SpaceManager::expand_lock());
size_t result = 0; size_t result = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
ChunkList* list = free_chunks(i); ChunkList* list = free_chunks(i);
if (list == NULL) { if (list == NULL) {
...@@ -1520,7 +1573,7 @@ size_t ChunkManager::sum_free_chunks() { ...@@ -1520,7 +1573,7 @@ size_t ChunkManager::sum_free_chunks() {
size_t ChunkManager::sum_free_chunks_count() { size_t ChunkManager::sum_free_chunks_count() {
assert_lock_strong(SpaceManager::expand_lock()); assert_lock_strong(SpaceManager::expand_lock());
size_t count = 0; size_t count = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
ChunkList* list = free_chunks(i); ChunkList* list = free_chunks(i);
if (list == NULL) { if (list == NULL) {
continue; continue;
...@@ -1532,15 +1585,9 @@ size_t ChunkManager::sum_free_chunks_count() { ...@@ -1532,15 +1585,9 @@ size_t ChunkManager::sum_free_chunks_count() {
} }
ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) { ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) {
switch (word_size) { ChunkIndex index = list_index(word_size);
case SpaceManager::SmallChunk : assert(index < HumongousIndex, "No humongous list");
return &_free_chunks[0]; return free_chunks(index);
case SpaceManager::MediumChunk :
return &_free_chunks[1];
default:
assert(word_size > SpaceManager::MediumChunk, "List inconsistency");
return &_free_chunks[2];
}
} }
void ChunkManager::free_chunks_put(Metachunk* chunk) { void ChunkManager::free_chunks_put(Metachunk* chunk) {
...@@ -1574,7 +1621,7 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { ...@@ -1574,7 +1621,7 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
slow_locked_verify(); slow_locked_verify();
Metachunk* chunk = NULL; Metachunk* chunk = NULL;
if (!SpaceManager::is_humongous(word_size)) { if (list_index(word_size) != HumongousIndex) {
ChunkList* free_list = find_free_chunks_list(word_size); ChunkList* free_list = find_free_chunks_list(word_size);
assert(free_list != NULL, "Sanity check"); assert(free_list != NULL, "Sanity check");
...@@ -1587,8 +1634,8 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { ...@@ -1587,8 +1634,8 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
// Remove the chunk as the head of the list. // Remove the chunk as the head of the list.
free_list->set_head(chunk->next()); free_list->set_head(chunk->next());
chunk->set_next(NULL);
// Chunk has been removed from the chunks free list. // Chunk is being removed from the chunks free list.
dec_free_chunks_total(chunk->capacity_word_size()); dec_free_chunks_total(chunk->capacity_word_size());
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
...@@ -1614,8 +1661,14 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) { ...@@ -1614,8 +1661,14 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
#ifdef ASSERT #ifdef ASSERT
chunk->set_is_free(false); chunk->set_is_free(false);
#endif #endif
} else {
return NULL;
} }
} }
// Remove it from the links to this freelist
chunk->set_next(NULL);
chunk->set_prev(NULL);
slow_locked_verify(); slow_locked_verify();
return chunk; return chunk;
} }
...@@ -1630,13 +1683,20 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { ...@@ -1630,13 +1683,20 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
return NULL; return NULL;
} }
assert(word_size <= chunk->word_size() || assert((word_size <= chunk->word_size()) ||
SpaceManager::is_humongous(chunk->word_size()), list_index(chunk->word_size() == HumongousIndex),
"Non-humongous variable sized chunk"); "Non-humongous variable sized chunk");
if (TraceMetadataChunkAllocation) { if (TraceMetadataChunkAllocation) {
tty->print("ChunkManager::chunk_freelist_allocate: chunk " size_t list_count;
PTR_FORMAT " size " SIZE_FORMAT " ", if (list_index(word_size) < HumongousIndex) {
chunk, chunk->word_size()); ChunkList* list = find_free_chunks_list(word_size);
list_count = list->sum_list_count();
} else {
list_count = humongous_dictionary()->total_count();
}
tty->print("ChunkManager::chunk_freelist_allocate: " PTR_FORMAT " chunk "
PTR_FORMAT " size " SIZE_FORMAT " count " SIZE_FORMAT " ",
this, chunk, chunk->word_size(), list_count);
locked_print_free_chunks(tty); locked_print_free_chunks(tty);
} }
...@@ -1651,10 +1711,42 @@ void ChunkManager::print_on(outputStream* out) { ...@@ -1651,10 +1711,42 @@ void ChunkManager::print_on(outputStream* out) {
// SpaceManager methods // SpaceManager methods
void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type,
size_t* chunk_word_size,
size_t* class_chunk_word_size) {
switch (type) {
case Metaspace::BootMetaspaceType:
*chunk_word_size = Metaspace::first_chunk_word_size();
*class_chunk_word_size = Metaspace::first_class_chunk_word_size();
break;
case Metaspace::ROMetaspaceType:
*chunk_word_size = SharedReadOnlySize / wordSize;
*class_chunk_word_size = ClassSpecializedChunk;
break;
case Metaspace::ReadWriteMetaspaceType:
*chunk_word_size = SharedReadWriteSize / wordSize;
*class_chunk_word_size = ClassSpecializedChunk;
break;
case Metaspace::AnonymousMetaspaceType:
case Metaspace::ReflectionMetaspaceType:
*chunk_word_size = SpecializedChunk;
*class_chunk_word_size = ClassSpecializedChunk;
break;
default:
*chunk_word_size = SmallChunk;
*class_chunk_word_size = ClassSmallChunk;
break;
}
assert(chunk_word_size != 0 && class_chunk_word_size != 0,
err_msg("Initial chunks sizes bad: data " SIZE_FORMAT
" class " SIZE_FORMAT,
chunk_word_size, class_chunk_word_size));
}
size_t SpaceManager::sum_free_in_chunks_in_use() const { size_t SpaceManager::sum_free_in_chunks_in_use() const {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t free = 0; size_t free = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* chunk = chunks_in_use(i); Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) { while (chunk != NULL) {
free += chunk->free_word_size(); free += chunk->free_word_size();
...@@ -1667,9 +1759,7 @@ size_t SpaceManager::sum_free_in_chunks_in_use() const { ...@@ -1667,9 +1759,7 @@ size_t SpaceManager::sum_free_in_chunks_in_use() const {
size_t SpaceManager::sum_waste_in_chunks_in_use() const { size_t SpaceManager::sum_waste_in_chunks_in_use() const {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t result = 0; size_t result = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
result += sum_waste_in_chunks_in_use(i); result += sum_waste_in_chunks_in_use(i);
} }
...@@ -1678,7 +1768,6 @@ size_t SpaceManager::sum_waste_in_chunks_in_use() const { ...@@ -1678,7 +1768,6 @@ size_t SpaceManager::sum_waste_in_chunks_in_use() const {
size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const { size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const {
size_t result = 0; size_t result = 0;
size_t count = 0;
Metachunk* chunk = chunks_in_use(index); Metachunk* chunk = chunks_in_use(index);
// Count the free space in all the chunk but not the // Count the free space in all the chunk but not the
// current chunk from which allocations are still being done. // current chunk from which allocations are still being done.
...@@ -1688,7 +1777,6 @@ size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const { ...@@ -1688,7 +1777,6 @@ size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const {
result += chunk->free_word_size(); result += chunk->free_word_size();
prev = chunk; prev = chunk;
chunk = chunk->next(); chunk = chunk->next();
count++;
} }
} }
return result; return result;
...@@ -1697,7 +1785,7 @@ size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const { ...@@ -1697,7 +1785,7 @@ size_t SpaceManager::sum_waste_in_chunks_in_use(ChunkIndex index) const {
size_t SpaceManager::sum_capacity_in_chunks_in_use() const { size_t SpaceManager::sum_capacity_in_chunks_in_use() const {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t sum = 0; size_t sum = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* chunk = chunks_in_use(i); Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) { while (chunk != NULL) {
// Just changed this sum += chunk->capacity_word_size(); // Just changed this sum += chunk->capacity_word_size();
...@@ -1711,7 +1799,7 @@ size_t SpaceManager::sum_capacity_in_chunks_in_use() const { ...@@ -1711,7 +1799,7 @@ size_t SpaceManager::sum_capacity_in_chunks_in_use() const {
size_t SpaceManager::sum_count_in_chunks_in_use() { size_t SpaceManager::sum_count_in_chunks_in_use() {
size_t count = 0; size_t count = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
count = count + sum_count_in_chunks_in_use(i); count = count + sum_count_in_chunks_in_use(i);
} }
...@@ -1732,7 +1820,7 @@ size_t SpaceManager::sum_count_in_chunks_in_use(ChunkIndex i) { ...@@ -1732,7 +1820,7 @@ size_t SpaceManager::sum_count_in_chunks_in_use(ChunkIndex i) {
size_t SpaceManager::sum_used_in_chunks_in_use() const { size_t SpaceManager::sum_used_in_chunks_in_use() const {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t used = 0; size_t used = 0;
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* chunk = chunks_in_use(i); Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) { while (chunk != NULL) {
used += chunk->used_word_size(); used += chunk->used_word_size();
...@@ -1744,19 +1832,17 @@ size_t SpaceManager::sum_used_in_chunks_in_use() const { ...@@ -1744,19 +1832,17 @@ size_t SpaceManager::sum_used_in_chunks_in_use() const {
void SpaceManager::locked_print_chunks_in_use_on(outputStream* st) const { void SpaceManager::locked_print_chunks_in_use_on(outputStream* st) const {
Metachunk* small_chunk = chunks_in_use(SmallIndex); for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
st->print_cr("SpaceManager: small chunk " PTR_FORMAT Metachunk* chunk = chunks_in_use(i);
" free " SIZE_FORMAT, st->print("SpaceManager: %s " PTR_FORMAT,
small_chunk, chunk_size_name(i), chunk);
small_chunk->free_word_size()); if (chunk != NULL) {
st->print_cr(" free " SIZE_FORMAT,
Metachunk* medium_chunk = chunks_in_use(MediumIndex); chunk->free_word_size());
st->print("medium chunk " PTR_FORMAT, medium_chunk); } else {
Metachunk* tail = current_chunk(); st->print_cr("");
st->print_cr(" current chunk " PTR_FORMAT, tail); }
}
Metachunk* head = chunks_in_use(HumongousIndex);
st->print_cr("humongous chunk " PTR_FORMAT, head);
vs_list()->chunk_manager()->locked_print_free_chunks(st); vs_list()->chunk_manager()->locked_print_free_chunks(st);
vs_list()->chunk_manager()->locked_print_sum_free_chunks(st); vs_list()->chunk_manager()->locked_print_sum_free_chunks(st);
...@@ -1772,18 +1858,28 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { ...@@ -1772,18 +1858,28 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) {
if (chunks_in_use(MediumIndex) == NULL && if (chunks_in_use(MediumIndex) == NULL &&
(!has_small_chunk_limit() || (!has_small_chunk_limit() ||
sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit)) { sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit)) {
chunk_word_size = (size_t) SpaceManager::SmallChunk; chunk_word_size = (size_t) small_chunk_size();
if (word_size + Metachunk::overhead() > SpaceManager::SmallChunk) { if (word_size + Metachunk::overhead() > small_chunk_size()) {
chunk_word_size = MediumChunk; chunk_word_size = medium_chunk_size();
} }
} else { } else {
chunk_word_size = MediumChunk; chunk_word_size = medium_chunk_size();
} }
// Might still need a humongous chunk // Might still need a humongous chunk. Enforce an
// eight word granularity to facilitate reuse (some
// wastage but better chance of reuse).
size_t if_humongous_sized_chunk =
align_size_up(word_size + Metachunk::overhead(),
HumongousChunkGranularity);
chunk_word_size = chunk_word_size =
MAX2((size_t) chunk_word_size, word_size + Metachunk::overhead()); MAX2((size_t) chunk_word_size, if_humongous_sized_chunk);
assert(!SpaceManager::is_humongous(word_size) ||
chunk_word_size == if_humongous_sized_chunk,
err_msg("Size calculation is wrong, word_size " SIZE_FORMAT
" chunk_word_size " SIZE_FORMAT,
word_size, chunk_word_size));
if (TraceMetadataHumongousAllocation && if (TraceMetadataHumongousAllocation &&
SpaceManager::is_humongous(word_size)) { SpaceManager::is_humongous(word_size)) {
gclog_or_tty->print_cr("Metadata humongous allocation:"); gclog_or_tty->print_cr("Metadata humongous allocation:");
...@@ -1805,15 +1901,21 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { ...@@ -1805,15 +1901,21 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) {
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
size_t words_left = 0;
size_t words_used = 0;
if (current_chunk() != NULL) {
words_left = current_chunk()->free_word_size();
words_used = current_chunk()->used_word_size();
}
gclog_or_tty->print_cr("SpaceManager::grow_and_allocate for " SIZE_FORMAT gclog_or_tty->print_cr("SpaceManager::grow_and_allocate for " SIZE_FORMAT
" words " SIZE_FORMAT " space left", " words " SIZE_FORMAT " words used " SIZE_FORMAT
word_size, current_chunk() != NULL ? " words left",
current_chunk()->free_word_size() : 0); word_size, words_used, words_left);
} }
// Get another chunk out of the virtual space // Get another chunk out of the virtual space
size_t grow_chunks_by_words = calc_chunk_size(word_size); size_t grow_chunks_by_words = calc_chunk_size(word_size);
Metachunk* next = vs_list()->get_new_chunk(word_size, grow_chunks_by_words); Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words);
// If a chunk was available, add it to the in-use chunk list // If a chunk was available, add it to the in-use chunk list
// and do an allocation from it. // and do an allocation from it.
...@@ -1828,7 +1930,7 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) { ...@@ -1828,7 +1930,7 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) {
void SpaceManager::print_on(outputStream* st) const { void SpaceManager::print_on(outputStream* st) const {
for (ChunkIndex i = SmallIndex; for (ChunkIndex i = ZeroIndex;
i < NumberOfInUseLists ; i < NumberOfInUseLists ;
i = next_chunk_index(i) ) { i = next_chunk_index(i) ) {
st->print_cr(" chunks_in_use " PTR_FORMAT " chunk size " PTR_FORMAT, st->print_cr(" chunks_in_use " PTR_FORMAT " chunk size " PTR_FORMAT,
...@@ -1847,12 +1949,18 @@ void SpaceManager::print_on(outputStream* st) const { ...@@ -1847,12 +1949,18 @@ void SpaceManager::print_on(outputStream* st) const {
} }
} }
SpaceManager::SpaceManager(Mutex* lock, VirtualSpaceList* vs_list) : SpaceManager::SpaceManager(Mutex* lock,
VirtualSpaceList* vs_list) :
_vs_list(vs_list), _vs_list(vs_list),
_allocation_total(0), _allocation_total(0),
_lock(lock) { _lock(lock)
{
initialize();
}
void SpaceManager::initialize() {
Metadebug::init_allocation_fail_alot_count(); Metadebug::init_allocation_fail_alot_count();
for (ChunkIndex i = SmallIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) { for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
_chunks_in_use[i] = NULL; _chunks_in_use[i] = NULL;
} }
_current_chunk = NULL; _current_chunk = NULL;
...@@ -1885,30 +1993,37 @@ SpaceManager::~SpaceManager() { ...@@ -1885,30 +1993,37 @@ SpaceManager::~SpaceManager() {
// Add all the chunks in use by this space manager // Add all the chunks in use by this space manager
// to the global list of free chunks. // to the global list of free chunks.
// Small chunks. There is one _current_chunk for each // Follow each list of chunks-in-use and add them to the
// Metaspace. It could point to a small or medium chunk. // free lists. Each list is NULL terminated.
// Rather than determine which it is, follow the list of
// small chunks to add them to the free list for (ChunkIndex i = ZeroIndex; i < HumongousIndex; i = next_chunk_index(i)) {
Metachunk* small_chunk = chunks_in_use(SmallIndex); if (TraceMetadataChunkAllocation && Verbose) {
chunk_manager->free_small_chunks()->add_at_head(small_chunk); gclog_or_tty->print_cr("returned %d %s chunks to freelist",
set_chunks_in_use(SmallIndex, NULL); sum_count_in_chunks_in_use(i),
chunk_size_name(i));
// After the small chunk are the medium chunks }
Metachunk* medium_chunk = chunks_in_use(MediumIndex); Metachunk* chunks = chunks_in_use(i);
assert(medium_chunk == NULL || chunk_manager->free_chunks(i)->add_at_head(chunks);
medium_chunk->word_size() == MediumChunk, set_chunks_in_use(i, NULL);
"Chunk is on the wrong list"); if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr("updated freelist count %d %s",
if (medium_chunk != NULL) { chunk_manager->free_chunks(i)->sum_list_count(),
Metachunk* head = medium_chunk; chunk_size_name(i));
// If there is a medium chunk then the _current_chunk can only }
// point to the last medium chunk. assert(i != HumongousIndex, "Humongous chunks are handled explicitly later");
Metachunk* tail = current_chunk();
chunk_manager->free_medium_chunks()->add_at_head(head, tail);
set_chunks_in_use(MediumIndex, NULL);
} }
// The medium chunk case may be optimized by passing the head and
// tail of the medium chunk list to add_at_head(). The tail is often
// the current chunk but there are probably exceptions.
// Humongous chunks // Humongous chunks
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr("returned %d %s humongous chunks to dictionary",
sum_count_in_chunks_in_use(HumongousIndex),
chunk_size_name(HumongousIndex));
gclog_or_tty->print("Humongous chunk dictionary: ");
}
// Humongous chunks are never the current chunk. // Humongous chunks are never the current chunk.
Metachunk* humongous_chunks = chunks_in_use(HumongousIndex); Metachunk* humongous_chunks = chunks_in_use(HumongousIndex);
...@@ -1916,14 +2031,65 @@ SpaceManager::~SpaceManager() { ...@@ -1916,14 +2031,65 @@ SpaceManager::~SpaceManager() {
#ifdef ASSERT #ifdef ASSERT
humongous_chunks->set_is_free(true); humongous_chunks->set_is_free(true);
#endif #endif
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
humongous_chunks,
humongous_chunks->word_size());
}
assert(humongous_chunks->word_size() == (size_t)
align_size_up(humongous_chunks->word_size(),
HumongousChunkGranularity),
err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT
" granularity " SIZE_FORMAT,
humongous_chunks->word_size(), HumongousChunkGranularity));
Metachunk* next_humongous_chunks = humongous_chunks->next(); Metachunk* next_humongous_chunks = humongous_chunks->next();
chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks); chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks);
humongous_chunks = next_humongous_chunks; humongous_chunks = next_humongous_chunks;
} }
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print_cr("");
gclog_or_tty->print_cr("updated dictionary count %d %s",
chunk_manager->humongous_dictionary()->total_count(),
chunk_size_name(HumongousIndex));
}
set_chunks_in_use(HumongousIndex, NULL); set_chunks_in_use(HumongousIndex, NULL);
chunk_manager->slow_locked_verify(); chunk_manager->slow_locked_verify();
} }
const char* SpaceManager::chunk_size_name(ChunkIndex index) const {
switch (index) {
case SpecializedIndex:
return "Specialized";
case SmallIndex:
return "Small";
case MediumIndex:
return "Medium";
case HumongousIndex:
return "Humongous";
default:
return NULL;
}
}
ChunkIndex ChunkManager::list_index(size_t size) {
switch (size) {
case SpecializedChunk:
assert(SpecializedChunk == ClassSpecializedChunk,
"Need branch for ClassSpecializedChunk");
return SpecializedIndex;
case SmallChunk:
case ClassSmallChunk:
return SmallIndex;
case MediumChunk:
case ClassMediumChunk:
return MediumIndex;
default:
assert(size > MediumChunk && size > ClassMediumChunk,
"Not a humongous chunk");
return HumongousIndex;
}
}
void SpaceManager::deallocate(MetaWord* p, size_t word_size) { void SpaceManager::deallocate(MetaWord* p, size_t word_size) {
assert_lock_strong(_lock); assert_lock_strong(_lock);
size_t min_size = TreeChunk<Metablock, FreeList>::min_size(); size_t min_size = TreeChunk<Metablock, FreeList>::min_size();
...@@ -1942,52 +2108,13 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { ...@@ -1942,52 +2108,13 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
// Find the correct list and and set the current // Find the correct list and and set the current
// chunk for that list. // chunk for that list.
switch (new_chunk->word_size()) { ChunkIndex index = ChunkManager::list_index(new_chunk->word_size());
case SpaceManager::SmallChunk :
if (chunks_in_use(SmallIndex) == NULL) {
// First chunk to add to the list
set_chunks_in_use(SmallIndex, new_chunk);
} else {
assert(current_chunk()->word_size() == SpaceManager::SmallChunk,
err_msg( "Incorrect mix of sizes in chunk list "
SIZE_FORMAT " new chunk " SIZE_FORMAT,
current_chunk()->word_size(), new_chunk->word_size()));
current_chunk()->set_next(new_chunk);
}
// Make current chunk
set_current_chunk(new_chunk);
break;
case SpaceManager::MediumChunk :
if (chunks_in_use(MediumIndex) == NULL) {
// About to add the first medium chunk so teminate the
// small chunk list. In general once medium chunks are
// being added, we're past the need for small chunks.
if (current_chunk() != NULL) {
// Only a small chunk or the initial chunk could be
// the current chunk if this is the first medium chunk.
assert(current_chunk()->word_size() == SpaceManager::SmallChunk ||
chunks_in_use(SmallIndex) == NULL,
err_msg("Should be a small chunk or initial chunk, current chunk "
SIZE_FORMAT " new chunk " SIZE_FORMAT,
current_chunk()->word_size(), new_chunk->word_size()));
current_chunk()->set_next(NULL);
}
// First chunk to add to the list
set_chunks_in_use(MediumIndex, new_chunk);
} else { if (index != HumongousIndex) {
// As a minimum the first medium chunk added would
// have become the _current_chunk
// so the _current_chunk has to be non-NULL here
// (although not necessarily still the first medium chunk).
assert(current_chunk()->word_size() == SpaceManager::MediumChunk,
"A medium chunk should the current chunk");
current_chunk()->set_next(new_chunk);
}
// Make current chunk
set_current_chunk(new_chunk); set_current_chunk(new_chunk);
break; new_chunk->set_next(chunks_in_use(index));
default: { set_chunks_in_use(index, new_chunk);
} else {
// For null class loader data and DumpSharedSpaces, the first chunk isn't // For null class loader data and DumpSharedSpaces, the first chunk isn't
// small, so small will be null. Link this first chunk as the current // small, so small will be null. Link this first chunk as the current
// chunk. // chunk.
...@@ -2004,7 +2131,6 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { ...@@ -2004,7 +2131,6 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
assert(new_chunk->word_size() > MediumChunk, "List inconsistency"); assert(new_chunk->word_size() > MediumChunk, "List inconsistency");
} }
}
assert(new_chunk->is_empty(), "Not ready for reuse"); assert(new_chunk->is_empty(), "Not ready for reuse");
if (TraceMetadataChunkAllocation && Verbose) { if (TraceMetadataChunkAllocation && Verbose) {
...@@ -2015,6 +2141,22 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) { ...@@ -2015,6 +2141,22 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
} }
} }
Metachunk* SpaceManager::get_new_chunk(size_t word_size,
size_t grow_chunks_by_words) {
Metachunk* next = vs_list()->get_new_chunk(word_size,
grow_chunks_by_words,
medium_chunk_bunch());
if (TraceMetadataHumongousAllocation &&
SpaceManager::is_humongous(next->word_size())) {
gclog_or_tty->print_cr(" new humongous chunk word size " PTR_FORMAT,
next->word_size());
}
return next;
}
MetaWord* SpaceManager::allocate(size_t word_size) { MetaWord* SpaceManager::allocate(size_t word_size) {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
...@@ -2090,12 +2232,7 @@ void SpaceManager::verify() { ...@@ -2090,12 +2232,7 @@ void SpaceManager::verify() {
// verfication of chunks does not work since // verfication of chunks does not work since
// being in the dictionary alters a chunk. // being in the dictionary alters a chunk.
if (block_freelists()->total_size() == 0) { if (block_freelists()->total_size() == 0) {
// Skip the small chunks because their next link points to for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
// medium chunks. This is because the small chunk is the
// current chunk (for allocations) until it is full and the
// the addition of the next chunk does not NULL the next
// like of the small chunk.
for (ChunkIndex i = MediumIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* curr = chunks_in_use(i); Metachunk* curr = chunks_in_use(i);
while (curr != NULL) { while (curr != NULL) {
curr->verify(); curr->verify();
...@@ -2108,15 +2245,15 @@ void SpaceManager::verify() { ...@@ -2108,15 +2245,15 @@ void SpaceManager::verify() {
void SpaceManager::verify_chunk_size(Metachunk* chunk) { void SpaceManager::verify_chunk_size(Metachunk* chunk) {
assert(is_humongous(chunk->word_size()) || assert(is_humongous(chunk->word_size()) ||
chunk->word_size() == MediumChunk || chunk->word_size() == medium_chunk_size() ||
chunk->word_size() == SmallChunk, chunk->word_size() == small_chunk_size() ||
chunk->word_size() == specialized_chunk_size(),
"Chunk size is wrong"); "Chunk size is wrong");
return; return;
} }
#ifdef ASSERT #ifdef ASSERT
void SpaceManager::verify_allocation_total() { void SpaceManager::verify_allocation_total() {
#if 0
// Verification is only guaranteed at a safepoint. // Verification is only guaranteed at a safepoint.
if (SafepointSynchronize::is_at_safepoint()) { if (SafepointSynchronize::is_at_safepoint()) {
gclog_or_tty->print_cr("Chunk " PTR_FORMAT " allocation_total " SIZE_FORMAT gclog_or_tty->print_cr("Chunk " PTR_FORMAT " allocation_total " SIZE_FORMAT
...@@ -2129,7 +2266,6 @@ void SpaceManager::verify_allocation_total() { ...@@ -2129,7 +2266,6 @@ void SpaceManager::verify_allocation_total() {
assert(allocation_total() == sum_used_in_chunks_in_use(), assert(allocation_total() == sum_used_in_chunks_in_use(),
err_msg("allocation total is not consistent %d vs %d", err_msg("allocation total is not consistent %d vs %d",
allocation_total(), sum_used_in_chunks_in_use())); allocation_total(), sum_used_in_chunks_in_use()));
#endif
} }
#endif #endif
...@@ -2142,7 +2278,7 @@ void SpaceManager::dump(outputStream* const out) const { ...@@ -2142,7 +2278,7 @@ void SpaceManager::dump(outputStream* const out) const {
size_t capacity = 0; size_t capacity = 0;
// Add up statistics for all chunks in this SpaceManager. // Add up statistics for all chunks in this SpaceManager.
for (ChunkIndex index = SmallIndex; for (ChunkIndex index = ZeroIndex;
index < NumberOfInUseLists; index < NumberOfInUseLists;
index = next_chunk_index(index)) { index = next_chunk_index(index)) {
for (Metachunk* curr = chunks_in_use(index); for (Metachunk* curr = chunks_in_use(index);
...@@ -2160,7 +2296,7 @@ void SpaceManager::dump(outputStream* const out) const { ...@@ -2160,7 +2296,7 @@ void SpaceManager::dump(outputStream* const out) const {
} }
} }
size_t free = current_chunk()->free_word_size(); size_t free = current_chunk() == NULL ? 0 : current_chunk()->free_word_size();
// Free space isn't wasted. // Free space isn't wasted.
waste -= free; waste -= free;
...@@ -2171,25 +2307,18 @@ void SpaceManager::dump(outputStream* const out) const { ...@@ -2171,25 +2307,18 @@ void SpaceManager::dump(outputStream* const out) const {
#ifndef PRODUCT #ifndef PRODUCT
void SpaceManager::mangle_freed_chunks() { void SpaceManager::mangle_freed_chunks() {
for (ChunkIndex index = SmallIndex; for (ChunkIndex index = ZeroIndex;
index < NumberOfInUseLists; index < NumberOfInUseLists;
index = next_chunk_index(index)) { index = next_chunk_index(index)) {
for (Metachunk* curr = chunks_in_use(index); for (Metachunk* curr = chunks_in_use(index);
curr != NULL; curr != NULL;
curr = curr->next()) { curr = curr->next()) {
// Try to detect incorrectly terminated small chunk
// list.
assert(index == MediumIndex || curr != chunks_in_use(MediumIndex),
err_msg("Mangling medium chunks in small chunks? "
"curr " PTR_FORMAT " medium list " PTR_FORMAT,
curr, chunks_in_use(MediumIndex)));
curr->mangle(); curr->mangle();
} }
} }
} }
#endif // PRODUCT #endif // PRODUCT
// MetaspaceAux // MetaspaceAux
size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) { size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) {
...@@ -2236,7 +2365,7 @@ size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) { ...@@ -2236,7 +2365,7 @@ size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) {
return reserved * BytesPerWord; return reserved * BytesPerWord;
} }
size_t MetaspaceAux::min_chunk_size() { return SpaceManager::MediumChunk; } size_t MetaspaceAux::min_chunk_size() { return Metaspace::first_chunk_word_size(); }
size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) { size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) {
ChunkManager* chunk = (mdtype == Metaspace::ClassType) ? ChunkManager* chunk = (mdtype == Metaspace::ClassType) ?
...@@ -2316,26 +2445,44 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) { ...@@ -2316,26 +2445,44 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) {
// Print total fragmentation for class and data metaspaces separately // Print total fragmentation for class and data metaspaces separately
void MetaspaceAux::print_waste(outputStream* out) { void MetaspaceAux::print_waste(outputStream* out) {
size_t small_waste = 0, medium_waste = 0, large_waste = 0; size_t specialized_waste = 0, small_waste = 0, medium_waste = 0, large_waste = 0;
size_t cls_small_waste = 0, cls_medium_waste = 0, cls_large_waste = 0; size_t specialized_count = 0, small_count = 0, medium_count = 0, large_count = 0;
size_t cls_specialized_waste = 0, cls_small_waste = 0, cls_medium_waste = 0, cls_large_waste = 0;
size_t cls_specialized_count = 0, cls_small_count = 0, cls_medium_count = 0, cls_large_count = 0;
ClassLoaderDataGraphMetaspaceIterator iter; ClassLoaderDataGraphMetaspaceIterator iter;
while (iter.repeat()) { while (iter.repeat()) {
Metaspace* msp = iter.get_next(); Metaspace* msp = iter.get_next();
if (msp != NULL) { 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);
small_waste += msp->vsm()->sum_waste_in_chunks_in_use(SmallIndex); small_waste += msp->vsm()->sum_waste_in_chunks_in_use(SmallIndex);
small_count += msp->vsm()->sum_count_in_chunks_in_use(SmallIndex);
medium_waste += msp->vsm()->sum_waste_in_chunks_in_use(MediumIndex); medium_waste += msp->vsm()->sum_waste_in_chunks_in_use(MediumIndex);
medium_count += msp->vsm()->sum_count_in_chunks_in_use(MediumIndex);
large_waste += msp->vsm()->sum_waste_in_chunks_in_use(HumongousIndex); large_waste += msp->vsm()->sum_waste_in_chunks_in_use(HumongousIndex);
large_count += msp->vsm()->sum_count_in_chunks_in_use(HumongousIndex);
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);
cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex); cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex);
cls_small_count += msp->class_vsm()->sum_count_in_chunks_in_use(SmallIndex);
cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex); cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex);
cls_medium_count += msp->class_vsm()->sum_count_in_chunks_in_use(MediumIndex);
cls_large_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(HumongousIndex); cls_large_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(HumongousIndex);
cls_large_count += msp->class_vsm()->sum_count_in_chunks_in_use(HumongousIndex);
} }
} }
out->print_cr("Total fragmentation waste (words) doesn't count free space"); out->print_cr("Total fragmentation waste (words) doesn't count free space");
out->print(" data: small " SIZE_FORMAT " medium " SIZE_FORMAT, out->print_cr(" data: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", "
small_waste, medium_waste); SIZE_FORMAT " small(s) " SIZE_FORMAT ", "
out->print_cr(" class: small " SIZE_FORMAT, cls_small_waste); SIZE_FORMAT " medium(s) " SIZE_FORMAT,
specialized_count, specialized_waste, small_count,
small_waste, medium_count, medium_waste);
out->print_cr(" class: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", "
SIZE_FORMAT " small(s) " SIZE_FORMAT,
cls_specialized_count, cls_specialized_waste,
cls_small_count, cls_small_waste);
} }
// Dump global metaspace things from the end of ClassLoaderDataGraph // Dump global metaspace things from the end of ClassLoaderDataGraph
...@@ -2354,13 +2501,10 @@ void MetaspaceAux::verify_free_chunks() { ...@@ -2354,13 +2501,10 @@ void MetaspaceAux::verify_free_chunks() {
// Metaspace methods // Metaspace methods
size_t Metaspace::_first_chunk_word_size = 0; size_t Metaspace::_first_chunk_word_size = 0;
size_t Metaspace::_first_class_chunk_word_size = 0;
Metaspace::Metaspace(Mutex* lock, size_t word_size) { Metaspace::Metaspace(Mutex* lock, MetaspaceType type) {
initialize(lock, word_size); initialize(lock, type);
}
Metaspace::Metaspace(Mutex* lock) {
initialize(lock);
} }
Metaspace::~Metaspace() { Metaspace::~Metaspace() {
...@@ -2412,11 +2556,18 @@ void Metaspace::global_initialize() { ...@@ -2412,11 +2556,18 @@ void Metaspace::global_initialize() {
} }
} }
// Initialize this before initializing the VirtualSpaceList // Initialize these before initializing the VirtualSpaceList
_first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord; _first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
_first_chunk_word_size = align_word_size_up(_first_chunk_word_size);
// Make the first class chunk bigger than a medium chunk so it's not put
// on the medium chunk list. The next chunk will be small and progress
// from there. This size calculated by -version.
_first_class_chunk_word_size = MIN2((size_t)MediumChunk*6,
(ClassMetaspaceSize/BytesPerWord)*2);
_first_class_chunk_word_size = align_word_size_up(_first_class_chunk_word_size);
// Arbitrarily set the initial virtual space to a multiple // Arbitrarily set the initial virtual space to a multiple
// of the boot class loader size. // of the boot class loader size.
size_t word_size = VIRTUALSPACEMULTIPLIER * Metaspace::first_chunk_word_size(); size_t word_size = VIRTUALSPACEMULTIPLIER * first_chunk_word_size();
// Initialize the list of virtual spaces. // Initialize the list of virtual spaces.
_space_list = new VirtualSpaceList(word_size); _space_list = new VirtualSpaceList(word_size);
} }
...@@ -2431,23 +2582,8 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { ...@@ -2431,23 +2582,8 @@ void Metaspace::initialize_class_space(ReservedSpace rs) {
_class_space_list = new VirtualSpaceList(rs); _class_space_list = new VirtualSpaceList(rs);
} }
void Metaspace::initialize(Mutex* lock,
void Metaspace::initialize(Mutex* lock, size_t initial_size) { MetaspaceType type) {
// Use SmallChunk size if not specified. If specified, use this size for
// the data metaspace.
size_t word_size;
size_t class_word_size;
if (initial_size == 0) {
word_size = (size_t) SpaceManager::SmallChunk;
class_word_size = (size_t) SpaceManager::SmallChunk;
} else {
word_size = initial_size;
// Make the first class chunk bigger than a medium chunk so it's not put
// on the medium chunk list. The next chunk will be small and progress
// from there. This size calculated by -version.
class_word_size = MIN2((size_t)SpaceManager::MediumChunk*5,
(ClassMetaspaceSize/BytesPerWord)*2);
}
assert(space_list() != NULL, assert(space_list() != NULL,
"Metadata VirtualSpaceList has not been initialized"); "Metadata VirtualSpaceList has not been initialized");
...@@ -2456,6 +2592,11 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) { ...@@ -2456,6 +2592,11 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) {
if (_vsm == NULL) { if (_vsm == NULL) {
return; return;
} }
size_t word_size;
size_t class_word_size;
vsm()->get_initial_chunk_sizes(type,
&word_size,
&class_word_size);
assert(class_space_list() != NULL, assert(class_space_list() != NULL,
"Class VirtualSpaceList has not been initialized"); "Class VirtualSpaceList has not been initialized");
...@@ -2470,7 +2611,8 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) { ...@@ -2470,7 +2611,8 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) {
// Allocate chunk for metadata objects // Allocate chunk for metadata objects
Metachunk* new_chunk = Metachunk* new_chunk =
space_list()->current_virtual_space()->get_chunk_vs_with_expand(word_size); space_list()->get_initialization_chunk(word_size,
vsm()->medium_chunk_bunch());
assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks"); assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
if (new_chunk != NULL) { if (new_chunk != NULL) {
// Add to this manager's list of chunks in use and current_chunk(). // Add to this manager's list of chunks in use and current_chunk().
...@@ -2479,12 +2621,18 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) { ...@@ -2479,12 +2621,18 @@ void Metaspace::initialize(Mutex* lock, size_t initial_size) {
// Allocate chunk for class metadata objects // Allocate chunk for class metadata objects
Metachunk* class_chunk = Metachunk* class_chunk =
class_space_list()->current_virtual_space()->get_chunk_vs_with_expand(class_word_size); class_space_list()->get_initialization_chunk(class_word_size,
class_vsm()->medium_chunk_bunch());
if (class_chunk != NULL) { if (class_chunk != NULL) {
class_vsm()->add_chunk(class_chunk, true); class_vsm()->add_chunk(class_chunk, true);
} }
} }
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) { MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) {
// DumpSharedSpaces doesn't use class metadata area (yet) // DumpSharedSpaces doesn't use class metadata area (yet)
if (mdtype == ClassType && !DumpSharedSpaces) { if (mdtype == ClassType && !DumpSharedSpaces) {
...@@ -2610,6 +2758,12 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, ...@@ -2610,6 +2758,12 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
// If result is still null, we are out of memory. // If result is still null, we are out of memory.
if (result == NULL) { if (result == NULL) {
if (Verbose && TraceMetadataChunkAllocation) {
gclog_or_tty->print_cr("Metaspace allocation failed for size "
SIZE_FORMAT, word_size);
if (loader_data->metaspace_or_null() != NULL) loader_data->metaspace_or_null()->dump(gclog_or_tty);
MetaspaceAux::dump(gclog_or_tty);
}
// -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support // -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
report_java_out_of_memory("Metadata space"); report_java_out_of_memory("Metadata space");
......
...@@ -87,11 +87,23 @@ class Metaspace : public CHeapObj<mtClass> { ...@@ -87,11 +87,23 @@ class Metaspace : public CHeapObj<mtClass> {
public: public:
enum MetadataType {ClassType, NonClassType}; enum MetadataType {ClassType, NonClassType};
enum MetaspaceType {
StandardMetaspaceType,
BootMetaspaceType,
ROMetaspaceType,
ReadWriteMetaspaceType,
AnonymousMetaspaceType,
ReflectionMetaspaceType
};
private: private:
void initialize(Mutex* lock, size_t initial_size = 0); void initialize(Mutex* lock, MetaspaceType type);
// Align up the word size to the allocation word size
static size_t align_word_size_up(size_t);
static size_t _first_chunk_word_size; static size_t _first_chunk_word_size;
static size_t _first_class_chunk_word_size;
SpaceManager* _vsm; SpaceManager* _vsm;
SpaceManager* vsm() const { return _vsm; } SpaceManager* vsm() const { return _vsm; }
...@@ -110,8 +122,7 @@ class Metaspace : public CHeapObj<mtClass> { ...@@ -110,8 +122,7 @@ class Metaspace : public CHeapObj<mtClass> {
public: public:
Metaspace(Mutex* lock, size_t initial_size); Metaspace(Mutex* lock, MetaspaceType type);
Metaspace(Mutex* lock);
~Metaspace(); ~Metaspace();
// Initialize globals for Metaspace // Initialize globals for Metaspace
...@@ -119,6 +130,7 @@ class Metaspace : public CHeapObj<mtClass> { ...@@ -119,6 +130,7 @@ class Metaspace : public CHeapObj<mtClass> {
static void initialize_class_space(ReservedSpace rs); static void initialize_class_space(ReservedSpace rs);
static size_t first_chunk_word_size() { return _first_chunk_word_size; } 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; }
char* bottom() const; char* bottom() const;
size_t used_words(MetadataType mdtype) const; size_t used_words(MetadataType mdtype) const;
......
...@@ -2217,7 +2217,8 @@ class CommandLineFlags { ...@@ -2217,7 +2217,8 @@ class CommandLineFlags {
develop(bool, TraceClassLoaderData, false, \ develop(bool, TraceClassLoaderData, false, \
"Trace class loader loader_data lifetime") \ "Trace class loader loader_data lifetime") \
\ \
product(uintx, InitialBootClassLoaderMetaspaceSize, 3*M, \ product(uintx, InitialBootClassLoaderMetaspaceSize, \
NOT_LP64(2200*K) LP64_ONLY(4*M), \
"Initial size of the boot class loader data metaspace") \ "Initial size of the boot class loader data metaspace") \
\ \
product(bool, TraceGen0Time, false, \ product(bool, TraceGen0Time, false, \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册