src/share/vm/memory/metaspace.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hsx-gc Cdiff src/share/vm/memory/metaspace.cpp
src/share/vm/memory/metaspace.cpp
Print this page
*** 28,38 ****
#include "memory/freeList.hpp"
#include "memory/collectorPolicy.hpp"
#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"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
--- 28,37 ----
*** 47,58 ****
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
typedef BinaryTreeDictionary<Metachunk, FreeList> ChunkTreeDictionary;
! // Define this macro to enable slow integrity checking of
! // the free chunk lists
const bool metaspace_slow_verify = false;
// Parameters for stress mode testing
const uint metadata_deallocate_a_lot_block = 10;
const uint metadata_deallocate_a_lock_chunk = 3;
--- 46,57 ----
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
typedef BinaryTreeDictionary<Metachunk, FreeList> ChunkTreeDictionary;
!
! // Set this constant to enable slow integrity checking of the free chunk lists
const bool metaspace_slow_verify = false;
// Parameters for stress mode testing
const uint metadata_deallocate_a_lot_block = 10;
const uint metadata_deallocate_a_lock_chunk = 3;
*** 90,127 ****
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.
// SpecializedChunk
// SmallChunk
// MediumChunk
// HumongousChunk
ChunkList _free_chunks[NumberOfFreeLists];
-
// HumongousChunk
ChunkTreeDictionary _humongous_dictionary;
// ChunkManager in all lists of this type
size_t _free_chunks_total;
--- 89,110 ----
*** 228,238 ****
// Used to manage the free list of Metablocks (a block corresponds
// 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.
const static int WasteMultiplier = 4;
--- 211,220 ----
*** 256,265 ****
--- 238,248 ----
}
void print_on(outputStream* st) const;
};
+ // A VirtualSpaceList node.
class VirtualSpaceNode : public CHeapObj<mtClass> {
friend class VirtualSpaceList;
// Link to next VirtualSpaceNode
VirtualSpaceNode* _next;
*** 412,422 ****
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");
--- 395,405 ----
void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
Metachunk* chunk = first_chunk();
Metachunk* invalid_chunk = (Metachunk*) top();
while (chunk < invalid_chunk ) {
! assert(chunk->is_marked_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");
*** 432,442 ****
while (chunk < invalid_chunk ) {
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
// Don't count the chunks on the free lists. Those are
// still part of the VirtualSpaceNode but not currently
// counted.
! if (!chunk->is_free()) {
count++;
}
chunk = (Metachunk*) next;
}
return count;
--- 415,425 ----
while (chunk < invalid_chunk ) {
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
// Don't count the chunks on the free lists. Those are
// still part of the VirtualSpaceNode but not currently
// counted.
! if (!chunk->is_marked_free()) {
count++;
}
chunk = (Metachunk*) next;
}
return count;
*** 751,768 ****
#ifdef ASSERT
void verify_allocated_blocks_words();
#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_word_size = raw_bytes_size / BytesPerWord;
assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem");
return raw_word_size;
}
--- 734,748 ----
#ifdef ASSERT
void verify_allocated_blocks_words();
#endif
size_t get_raw_word_size(size_t word_size) {
size_t byte_size = word_size * BytesPerWord;
! 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");
return raw_word_size;
}
*** 811,831 ****
}
delete _dictionary;
}
}
- 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);
if (dictionary() == NULL) {
_dictionary = new BlockTreeDictionary();
}
dictionary()->return_chunk(free_chunk);
}
--- 791,802 ----
}
delete _dictionary;
}
}
void BlockFreelist::return_block(MetaWord* p, size_t word_size) {
! Metablock* free_chunk = ::new (p) Metablock(word_size);
if (dictionary() == NULL) {
_dictionary = new BlockTreeDictionary();
}
dictionary()->return_chunk(free_chunk);
}
*** 1067,1077 ****
} else {
humongous_dictionary()->remove_chunk(chunk);
}
// Chunk is being removed from the chunks free list.
! dec_free_chunks_total(chunk->capacity_word_size());
}
// Walk the list of VirtualSpaceNodes and delete
// nodes with a 0 container_count. Remove Metachunks in
// the node from their respective freelists.
--- 1038,1048 ----
} else {
humongous_dictionary()->remove_chunk(chunk);
}
// Chunk is being removed from the chunks free list.
! dec_free_chunks_total(chunk->word_size());
}
// Walk the list of VirtualSpaceNodes and delete
// nodes with a 0 container_count. Remove Metachunks in
// the node from their respective freelists.
*** 1758,1768 ****
assert_lock_strong(SpaceManager::expand_lock());
ChunkList* free_list = find_free_chunks_list(chunk->word_size());
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());
slow_locked_verify();
}
void ChunkManager::chunk_freelist_deallocate(Metachunk* chunk) {
// The deallocation of a chunk originates in the freelist
--- 1729,1739 ----
assert_lock_strong(SpaceManager::expand_lock());
ChunkList* free_list = find_free_chunks_list(chunk->word_size());
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->word_size());
slow_locked_verify();
}
void ChunkManager::chunk_freelist_deallocate(Metachunk* chunk) {
// The deallocation of a chunk originates in the freelist
*** 1820,1838 ****
chunk->word_size(), word_size, waste);
}
}
// Chunk is being removed from the chunks free list.
! dec_free_chunks_total(chunk->capacity_word_size());
// Remove it from the links to this freelist
chunk->set_next(NULL);
chunk->set_prev(NULL);
#ifdef ASSERT
// Chunk is no longer on any freelist. Setting to false make container_count_slow()
// work.
! chunk->set_is_free(false);
#endif
chunk->container()->inc_container_count();
slow_locked_verify();
return chunk;
--- 1791,1809 ----
chunk->word_size(), word_size, waste);
}
}
// Chunk is being removed from the chunks free list.
! dec_free_chunks_total(chunk->word_size());
// Remove it from the links to this freelist
chunk->set_next(NULL);
chunk->set_prev(NULL);
#ifdef ASSERT
// Chunk is no longer on any freelist. Setting to false make container_count_slow()
// work.
! chunk->set_is_marked_free(false);
#endif
chunk->container()->inc_container_count();
slow_locked_verify();
return chunk;
*** 1960,1970 ****
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t sum = 0;
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();
chunk = chunk->next();
}
}
return sum;
}
--- 1931,1941 ----
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t sum = 0;
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) {
! sum += chunk->word_size();
chunk = chunk->next();
}
}
return sum;
}
*** 2208,2218 ****
assert(cur->container() != NULL, "Container should have been set");
cur->container()->dec_container_count();
// 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);
list->return_chunk_at_head(cur);
cur = next;
}
}
--- 2179,2189 ----
assert(cur->container() != NULL, "Container should have been set");
cur->container()->dec_container_count();
// Capture the next link before it is changed
// by the call to return_chunk_at_head();
Metachunk* next = cur->next();
! DEBUG_ONLY(cur->set_is_marked_free(true);)
list->return_chunk_at_head(cur);
cur = next;
}
}
*** 2280,2290 ****
// Humongous chunks are never the current chunk.
Metachunk* humongous_chunks = chunks_in_use(HumongousIndex);
while (humongous_chunks != NULL) {
#ifdef ASSERT
! humongous_chunks->set_is_free(true);
#endif
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
humongous_chunks,
humongous_chunks->word_size());
--- 2251,2261 ----
// Humongous chunks are never the current chunk.
Metachunk* humongous_chunks = chunks_in_use(HumongousIndex);
while (humongous_chunks != NULL) {
#ifdef ASSERT
! humongous_chunks->set_is_marked_free(true);
#endif
if (TraceMetadataChunkAllocation && Verbose) {
gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
humongous_chunks,
humongous_chunks->word_size());
*** 2543,2553 ****
curr = curr->next()) {
out->print("%d) ", i++);
curr->print_on(out);
curr_total += curr->word_size();
used += curr->used_word_size();
! capacity += curr->capacity_word_size();
waste += curr->free_word_size() + curr->overhead();;
}
}
if (TraceMetadataChunkAllocation && Verbose) {
--- 2514,2524 ----
curr = curr->next()) {
out->print("%d) ", i++);
curr->print_on(out);
curr_total += curr->word_size();
used += curr->used_word_size();
! capacity += curr->word_size();
waste += curr->free_word_size() + curr->overhead();;
}
}
if (TraceMetadataChunkAllocation && Verbose) {
*** 3394,3404 ****
}
}
}
! Metablock* 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");
return NULL; // caller does a CHECK_NULL too
}
--- 3365,3375 ----
}
}
}
! 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");
return NULL; // caller does a CHECK_NULL too
}
*** 3413,3426 ****
assert(type > MetaspaceObj::UnknownType && type < MetaspaceObj::_number_of_types, "sanity");
Metaspace* space = read_only ? loader_data->ro_metaspace() : loader_data->rw_metaspace();
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);
}
MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;
// Try to allocate metadata.
--- 3384,3401 ----
assert(type > MetaspaceObj::UnknownType && type < MetaspaceObj::_number_of_types, "sanity");
Metaspace* space = read_only ? loader_data->ro_metaspace() : loader_data->rw_metaspace();
MetaWord* result = space->allocate(word_size, NonClassType);
if (result == NULL) {
report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite);
}
!
! 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;
// Try to allocate metadata.
*** 3441,3451 ****
report_metadata_oome(loader_data, word_size, mdtype, THREAD);
// Will not reach here.
return NULL;
}
! return Metablock::initialize(result, word_size);
}
void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) {
// If result is still null, we are out of memory.
if (Verbose && TraceMetadataChunkAllocation) {
--- 3416,3429 ----
report_metadata_oome(loader_data, word_size, mdtype, THREAD);
// Will not reach here.
return NULL;
}
! // 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) {
// If result is still null, we are out of memory.
if (Verbose && TraceMetadataChunkAllocation) {
src/share/vm/memory/metaspace.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File