8026391: The Metachunk header wastes memory

Reviewed-by: coleenp, jmasa
This commit is contained in:
Stefan Karlsson 2013-10-15 14:28:51 +02:00
parent 9f6e8976d0
commit f149d47720
11 changed files with 231 additions and 340 deletions

View file

@ -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 @@ volatile intptr_t MetaspaceGC::_capacity_until_GC = 0;
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 @@ class ChunkManager : public CHeapObj<mtInternal> {
// HumongousChunk
ChunkList _free_chunks[NumberOfFreeLists];
// HumongousChunk
ChunkTreeDictionary _humongous_dictionary;
@ -230,7 +213,6 @@ class ChunkManager : public CHeapObj<mtInternal> {
// 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 @@ class BlockFreelist VALUE_OBJ_CLASS_SPEC {
void print_on(outputStream* st) const;
};
// A VirtualSpaceList node.
class VirtualSpaceNode : public CHeapObj<mtClass> {
friend class VirtualSpaceList;
@ -414,13 +397,13 @@ void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
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 @@ uint VirtualSpaceNode::container_count_slow() {
// 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 @@ class SpaceManager : public CHeapObj<mtClass> {
#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 @@ BlockFreelist::~BlockFreelist() {
}
}
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 @@ void ChunkManager::remove_chunk(Metachunk* chunk) {
}
// 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 @@ void ChunkManager::free_chunks_put(Metachunk* chunk) {
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 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
}
// 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 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
#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 @@ size_t SpaceManager::sum_capacity_in_chunks_in_use() const {
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 @@ void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) {
// 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 @@ SpaceManager::~SpaceManager() {
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 @@ void SpaceManager::dump(outputStream* const out) const {
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 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
}
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 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
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 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
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) {