mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8026391: The Metachunk header wastes memory
Reviewed-by: coleenp, jmasa
This commit is contained in:
parent
9f6e8976d0
commit
f149d47720
11 changed files with 231 additions and 340 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue