< prev index next >
src/share/vm/memory/metaspace.cpp
Print this page
*** 529,541 ****
VirtualSpaceList(size_t word_size);
VirtualSpaceList(ReservedSpace rs);
size_t free_bytes();
! Metachunk* get_new_chunk(size_t word_size,
! size_t grow_chunks_by_words,
! size_t medium_chunk_bunch);
bool expand_node_by(VirtualSpaceNode* node,
size_t min_words,
size_t preferred_words);
--- 529,540 ----
VirtualSpaceList(size_t word_size);
VirtualSpaceList(ReservedSpace rs);
size_t free_bytes();
! Metachunk* get_new_chunk(size_t chunk_word_size,
! size_t suggested_commit_granularity);
bool expand_node_by(VirtualSpaceNode* node,
size_t min_words,
size_t preferred_words);
*** 685,703 ****
enum ChunkMultiples {
MediumChunkMultiple = 4
};
! bool is_class() { return _mdtype == Metaspace::ClassType; }
// Accessors
! size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; }
! size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
! size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
! size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
! size_t smallest_chunk_size() { return specialized_chunk_size(); }
size_t allocated_blocks_words() const { return _allocated_blocks_words; }
size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
size_t allocated_chunks_words() const { return _allocated_chunks_words; }
size_t allocated_chunks_count() const { return _allocated_chunks_count; }
--- 684,709 ----
enum ChunkMultiples {
MediumChunkMultiple = 4
};
! static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; }
! static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; }
! static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; }
!
! static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); }
// Accessors
! bool is_class() const { return _mdtype == Metaspace::ClassType; }
!
! size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); }
! size_t small_chunk_size() const { return small_chunk_size(is_class()); }
! size_t medium_chunk_size() const { return medium_chunk_size(is_class()); }
! size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); }
!
! size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; }
size_t allocated_blocks_words() const { return _allocated_blocks_words; }
size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
size_t allocated_chunks_words() const { return _allocated_chunks_words; }
size_t allocated_chunks_count() const { return _allocated_chunks_count; }
*** 716,740 ****
// Delete the portion of the running sums for this SpaceManager. That is,
// the globals running sums for the Metachunks and Metablocks are
// decremented for all the Metachunks in-use by this SpaceManager.
void dec_total_from_size_metrics();
! // 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_used_in_chunks_in_use() const;
size_t sum_free_in_chunks_in_use() const;
size_t sum_waste_in_chunks_in_use() const;
size_t sum_waste_in_chunks_in_use(ChunkIndex index ) const;
size_t sum_count_in_chunks_in_use();
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.
// Allocates a block from the current chunk
MetaWord* allocate(size_t word_size);
--- 722,749 ----
// Delete the portion of the running sums for this SpaceManager. That is,
// the globals running sums for the Metachunks and Metablocks are
// decremented for all the Metachunks in-use by this SpaceManager.
void dec_total_from_size_metrics();
! // Adjust the initial chunk size to match one of the fixed chunk list sizes,
! // or return the unadjusted size if the requested size is humongous.
! static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space);
! size_t adjust_initial_chunk_size(size_t requested) const;
!
! // Get the initial chunks size for this metaspace type.
! size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
size_t sum_capacity_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_waste_in_chunks_in_use() const;
size_t sum_waste_in_chunks_in_use(ChunkIndex index ) const;
size_t sum_count_in_chunks_in_use();
size_t sum_count_in_chunks_in_use(ChunkIndex i);
! Metachunk* get_new_chunk(size_t chunk_word_size);
// Block allocation and deallocation.
// Allocates a block from the current chunk
MetaWord* allocate(size_t word_size);
*** 1317,1350 ****
}
return false;
}
! Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
! size_t grow_chunks_by_words,
! size_t medium_chunk_bunch) {
// Allocate a chunk out of the current virtual space.
! Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
if (next != NULL) {
return next;
}
// The expand amount is currently only determined by the requested sizes
// and not how much committed memory is left in the current virtual space.
! size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words());
! size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words());
if (min_word_size >= preferred_word_size) {
// Can happen when humongous chunks are allocated.
preferred_word_size = min_word_size;
}
bool expanded = expand_by(min_word_size, preferred_word_size);
if (expanded) {
! next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
assert(next != NULL, "The allocation was expected to succeed after the expansion");
}
return next;
}
--- 1326,1357 ----
}
return false;
}
! Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) {
// Allocate a chunk out of the current virtual space.
! Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size);
if (next != NULL) {
return next;
}
// The expand amount is currently only determined by the requested sizes
// and not how much committed memory is left in the current virtual space.
! size_t min_word_size = align_size_up(chunk_word_size, Metaspace::commit_alignment_words());
! size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words());
if (min_word_size >= preferred_word_size) {
// Can happen when humongous chunks are allocated.
preferred_word_size = min_word_size;
}
bool expanded = expand_by(min_word_size, preferred_word_size);
if (expanded) {
! next = current_virtual_space()->get_chunk_vs(chunk_word_size);
assert(next != NULL, "The allocation was expected to succeed after the expansion");
}
return next;
}
*** 1881,1920 ****
}
}
// 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 {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t free = 0;
--- 1888,1949 ----
}
}
// SpaceManager methods
! size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) {
! size_t chunk_sizes[] = {
! specialized_chunk_size(is_class_space),
! small_chunk_size(is_class_space),
! medium_chunk_size(is_class_space)
! };
!
! // Adjust up to one of the fixed chunk sizes ...
! for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) {
! if (requested <= chunk_sizes[i]) {
! return chunk_sizes[i];
! }
! }
!
! // ... or return the size as a humongous chunk.
! return requested;
! }
!
! size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const {
! return adjust_initial_chunk_size(requested, is_class());
! }
!
! size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const {
! size_t requested;
!
! if (is_class()) {
switch (type) {
! case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break;
! case Metaspace::ROMetaspaceType: requested = ClassSpecializedChunk; break;
! case Metaspace::ReadWriteMetaspaceType: requested = ClassSpecializedChunk; break;
! case Metaspace::AnonymousMetaspaceType: requested = ClassSpecializedChunk; break;
! case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break;
! default: requested = ClassSmallChunk; break;
! }
! } else {
! switch (type) {
! case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break;
! case Metaspace::ROMetaspaceType: requested = SharedReadOnlySize / wordSize; break;
! case Metaspace::ReadWriteMetaspaceType: requested = SharedReadWriteSize / wordSize; break;
! case Metaspace::AnonymousMetaspaceType: requested = SpecializedChunk; break;
! case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break;
! default: requested = SmallChunk; break;
! }
! }
!
! // Adjust to one of the fixed chunk sizes (unless humongous)
! const size_t adjusted = adjust_initial_chunk_size(requested);
!
! assert(adjusted != 0, err_msg("Incorrect initial chunk size. Requested: "
! SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted));
!
! return adjusted;
}
size_t SpaceManager::sum_free_in_chunks_in_use() const {
MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
size_t free = 0;
*** 2100,2111 ****
" words left",
word_size, words_used, words_left);
}
// Get another chunk out of the virtual space
! size_t grow_chunks_by_words = calc_chunk_size(word_size);
! Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words);
MetaWord* mem = NULL;
// If a chunk was available, add it to the in-use chunk list
// and do an allocation from it.
--- 2129,2140 ----
" words left",
word_size, words_used, words_left);
}
// Get another chunk out of the virtual space
! size_t chunk_word_size = calc_chunk_size(word_size);
! Metachunk* next = get_new_chunk(chunk_word_size);
MetaWord* mem = NULL;
// If a chunk was available, add it to the in-use chunk list
// and do an allocation from it.
*** 2410,2427 ****
inc_used_metrics(remaining_words);
}
}
}
! Metachunk* SpaceManager::get_new_chunk(size_t word_size,
! size_t grow_chunks_by_words) {
// Get a chunk from the chunk freelist
! Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
if (next == NULL) {
! next = vs_list()->get_new_chunk(word_size,
! grow_chunks_by_words,
medium_chunk_bunch());
}
if (TraceMetadataHumongousAllocation && next != NULL &&
SpaceManager::is_humongous(next->word_size())) {
--- 2439,2454 ----
inc_used_metrics(remaining_words);
}
}
}
! Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) {
// Get a chunk from the chunk freelist
! Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size);
if (next == NULL) {
! next = vs_list()->get_new_chunk(chunk_word_size,
medium_chunk_bunch());
}
if (TraceMetadataHumongousAllocation && next != NULL &&
SpaceManager::is_humongous(next->word_size())) {
*** 3083,3093 ****
// The reserved space size may be bigger because of alignment, esp with UseLargePages
assert(rs.size() >= CompressedClassSpaceSize,
err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize));
assert(using_class_space(), "Must be using class space");
_class_space_list = new VirtualSpaceList(rs);
! _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk);
if (!_class_space_list->initialization_succeeded()) {
vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
}
}
--- 3110,3120 ----
// The reserved space size may be bigger because of alignment, esp with UseLargePages
assert(rs.size() >= CompressedClassSpaceSize,
err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize));
assert(using_class_space(), "Must be using class space");
_class_space_list = new VirtualSpaceList(rs);
! _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
if (!_class_space_list->initialization_succeeded()) {
vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
}
}
*** 3284,3353 ****
void Metaspace::post_initialize() {
MetaspaceGC::post_initialize();
}
! Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype,
! size_t chunk_word_size,
! size_t chunk_bunch) {
// Get a chunk from the chunk freelist
Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
! if (chunk != NULL) {
! return chunk;
}
! return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch);
}
! void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
! assert(space_list() != NULL,
! "Metadata VirtualSpaceList has not been initialized");
! assert(chunk_manager_metadata() != NULL,
! "Metadata ChunkManager has not been initialized");
_vsm = new SpaceManager(NonClassType, lock);
- if (_vsm == NULL) {
- return;
- }
- size_t word_size;
- size_t class_word_size;
- vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size);
if (using_class_space()) {
- assert(class_space_list() != NULL,
- "Class VirtualSpaceList has not been initialized");
- assert(chunk_manager_class() != NULL,
- "Class ChunkManager has not been initialized");
-
// Allocate SpaceManager for classes.
_class_vsm = new SpaceManager(ClassType, lock);
- if (_class_vsm == NULL) {
- return;
- }
}
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// Allocate chunk for metadata objects
! Metachunk* new_chunk = get_initialization_chunk(NonClassType,
! word_size,
! vsm()->medium_chunk_bunch());
! assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
! if (new_chunk != NULL) {
! // Add to this manager's list of chunks in use and current_chunk().
! vsm()->add_chunk(new_chunk, true);
! }
// Allocate chunk for class metadata objects
if (using_class_space()) {
! Metachunk* class_chunk = get_initialization_chunk(ClassType,
! class_word_size,
! class_vsm()->medium_chunk_bunch());
! if (class_chunk != NULL) {
! class_vsm()->add_chunk(class_chunk, true);
! }
}
_alloc_record_head = NULL;
_alloc_record_tail = NULL;
}
--- 3311,3376 ----
void Metaspace::post_initialize() {
MetaspaceGC::post_initialize();
}
! void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) {
! Metachunk* chunk = get_initialization_chunk(type, mdtype);
! if (chunk != NULL) {
! // Add to this manager's list of chunks in use and current_chunk().
! get_space_manager(mdtype)->add_chunk(chunk, true);
! }
! }
!
! Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) {
! size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
!
// Get a chunk from the chunk freelist
Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
!
! if (chunk == NULL) {
! chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size,
! get_space_manager(mdtype)->medium_chunk_bunch());
! }
!
! // For dumping shared archive, report error if allocation has failed.
! if (DumpSharedSpaces && chunk == NULL) {
! report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord);
}
! return chunk;
}
! void Metaspace::verify_global_initialization() {
! assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized");
! assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized");
! if (using_class_space()) {
! assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized");
! assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized");
! }
! }
+ void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
+ verify_global_initialization();
+
+ // Allocate SpaceManager for metadata objects.
_vsm = new SpaceManager(NonClassType, lock);
if (using_class_space()) {
// Allocate SpaceManager for classes.
_class_vsm = new SpaceManager(ClassType, lock);
}
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// Allocate chunk for metadata objects
! initialize_first_chunk(type, NonClassType);
// Allocate chunk for class metadata objects
if (using_class_space()) {
! initialize_first_chunk(type, ClassType);
}
_alloc_record_head = NULL;
_alloc_record_tail = NULL;
}
*** 3770,3780 ****
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// A size larger than VirtualSpaceSize (256k) and add one page to make it _not_ be
// vm_allocation_granularity aligned on Windows.
size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
large_size += (os::vm_page_size()/BytesPerWord);
! vs_list->get_new_chunk(large_size, large_size, 0);
}
static void test() {
test_reserved();
test_committed();
--- 3793,3803 ----
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// A size larger than VirtualSpaceSize (256k) and add one page to make it _not_ be
// vm_allocation_granularity aligned on Windows.
size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
large_size += (os::vm_page_size()/BytesPerWord);
! vs_list->get_new_chunk(large_size, 0);
}
static void test() {
test_reserved();
test_committed();
*** 3945,3950 ****
--- 3968,4023 ----
void TestVirtualSpaceNode_test() {
TestVirtualSpaceNodeTest::test();
TestVirtualSpaceNodeTest::test_is_available();
}
+
+ // The following test is placed here instead of a gtest / unittest file
+ // because the ChunkManager class is only available in this file.
+ class SpaceManagerTest : AllStatic {
+ friend void SpaceManager_test_adjust_initial_chunk_size();
+
+ static void test_adjust_initial_chunk_size(bool is_class) {
+ const size_t smallest = SpaceManager::smallest_chunk_size(is_class);
+ const size_t normal = SpaceManager::small_chunk_size(is_class);
+ const size_t medium = SpaceManager::medium_chunk_size(is_class);
+
+ #define test_adjust_initial_chunk_size(value, expected, is_class_value) \
+ do { \
+ size_t v = value; \
+ size_t e = expected; \
+ assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e, \
+ err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v)); \
+ } while (0)
+
+ // Smallest (specialized)
+ test_adjust_initial_chunk_size(1, smallest, is_class);
+ test_adjust_initial_chunk_size(smallest - 1, smallest, is_class);
+ test_adjust_initial_chunk_size(smallest, smallest, is_class);
+
+ // Small
+ test_adjust_initial_chunk_size(smallest + 1, normal, is_class);
+ test_adjust_initial_chunk_size(normal - 1, normal, is_class);
+ test_adjust_initial_chunk_size(normal, normal, is_class);
+
+ // Medium
+ test_adjust_initial_chunk_size(normal + 1, medium, is_class);
+ test_adjust_initial_chunk_size(medium - 1, medium, is_class);
+ test_adjust_initial_chunk_size(medium, medium, is_class);
+
+ // Humongous
+ test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class);
+
+ #undef test_adjust_initial_chunk_size
+ }
+
+ static void test_adjust_initial_chunk_size() {
+ test_adjust_initial_chunk_size(false);
+ test_adjust_initial_chunk_size(true);
+ }
+ };
+
+ void SpaceManager_test_adjust_initial_chunk_size() {
+ SpaceManagerTest::test_adjust_initial_chunk_size();
+ }
+
#endif
< prev index next >