mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +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
|
@ -28,7 +28,6 @@
|
||||||
#include "memory/binaryTreeDictionary.hpp"
|
#include "memory/binaryTreeDictionary.hpp"
|
||||||
#include "memory/freeList.hpp"
|
#include "memory/freeList.hpp"
|
||||||
#include "memory/freeBlockDictionary.hpp"
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
#include "memory/metablock.hpp"
|
|
||||||
#include "memory/metachunk.hpp"
|
#include "memory/metachunk.hpp"
|
||||||
#include "runtime/globals.hpp"
|
#include "runtime/globals.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
#include "memory/freeBlockDictionary.hpp"
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
#include "memory/metablock.hpp"
|
|
||||||
#include "memory/metachunk.hpp"
|
#include "memory/metachunk.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/freeBlockDictionary.hpp"
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
#include "memory/freeList.hpp"
|
#include "memory/freeList.hpp"
|
||||||
#include "memory/metablock.hpp"
|
|
||||||
#include "memory/metachunk.hpp"
|
#include "memory/metachunk.hpp"
|
||||||
#include "memory/sharedHeap.hpp"
|
#include "memory/sharedHeap.hpp"
|
||||||
#include "runtime/globals.hpp"
|
#include "runtime/globals.hpp"
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
|
||||||
#include "memory/allocation.hpp"
|
|
||||||
#include "memory/metablock.hpp"
|
|
||||||
#include "utilities/copy.hpp"
|
|
||||||
#include "utilities/debug.hpp"
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// Future modification
|
|
||||||
//
|
|
||||||
// The Metachunk can conceivable be replaced by the Chunk in
|
|
||||||
// allocation.hpp. Note that the latter Chunk is the space for
|
|
||||||
// allocation (allocations from the chunk are out of the space in
|
|
||||||
// the Chunk after the header for the Chunk) where as Metachunks
|
|
||||||
// point to space in a VirtualSpace. To replace Metachunks with
|
|
||||||
// Chunks, change Chunks so that they can be allocated out of a VirtualSpace.
|
|
||||||
size_t Metablock::_min_block_byte_size = sizeof(Metablock);
|
|
||||||
|
|
||||||
// New blocks returned by the Metaspace are zero initialized.
|
|
||||||
// We should fix the constructors to not assume this instead.
|
|
||||||
Metablock* Metablock::initialize(MetaWord* p, size_t word_size) {
|
|
||||||
if (p == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Metablock* result = (Metablock*) p;
|
|
||||||
|
|
||||||
// Clear the memory
|
|
||||||
Copy::fill_to_aligned_words((HeapWord*)result, word_size);
|
|
||||||
#ifdef ASSERT
|
|
||||||
result->set_word_size(word_size);
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef SHARE_VM_MEMORY_METABLOCK_HPP
|
|
||||||
#define SHARE_VM_MEMORY_METABLOCK_HPP
|
|
||||||
|
|
||||||
// Metablock are the unit of allocation from a Chunk. It is initialized
|
|
||||||
// with the size of the requested allocation. That size is overwritten
|
|
||||||
// once the allocation returns.
|
|
||||||
//
|
|
||||||
// A Metablock may be reused by its SpaceManager but are never moved between
|
|
||||||
// SpaceManagers. There is no explicit link to the Metachunk
|
|
||||||
// from which it was allocated. Metablock may be deallocated and
|
|
||||||
// put on a freelist but the space is never freed, rather
|
|
||||||
// the Metachunk it is a part of will be deallocated when it's
|
|
||||||
// associated class loader is collected.
|
|
||||||
|
|
||||||
class Metablock VALUE_OBJ_CLASS_SPEC {
|
|
||||||
friend class VMStructs;
|
|
||||||
private:
|
|
||||||
// Used to align the allocation (see below).
|
|
||||||
union block_t {
|
|
||||||
void* _data[3];
|
|
||||||
struct header_t {
|
|
||||||
size_t _word_size;
|
|
||||||
Metablock* _next;
|
|
||||||
Metablock* _prev;
|
|
||||||
} _header;
|
|
||||||
} _block;
|
|
||||||
static size_t _min_block_byte_size;
|
|
||||||
|
|
||||||
typedef union block_t Block;
|
|
||||||
typedef struct header_t Header;
|
|
||||||
const Block* block() const { return &_block; }
|
|
||||||
const Block::header_t* header() const { return &(block()->_header); }
|
|
||||||
public:
|
|
||||||
|
|
||||||
static Metablock* initialize(MetaWord* p, size_t word_size);
|
|
||||||
|
|
||||||
// This places the body of the block at a 2 word boundary
|
|
||||||
// because every block starts on a 2 word boundary. Work out
|
|
||||||
// how to make the body on a 2 word boundary if the block
|
|
||||||
// starts on a arbitrary boundary. JJJ
|
|
||||||
|
|
||||||
size_t word_size() const { return header()->_word_size; }
|
|
||||||
void set_word_size(size_t v) { _block._header._word_size = v; }
|
|
||||||
size_t size() const volatile { return _block._header._word_size; }
|
|
||||||
void set_size(size_t v) { _block._header._word_size = v; }
|
|
||||||
Metablock* next() const { return header()->_next; }
|
|
||||||
void set_next(Metablock* v) { _block._header._next = v; }
|
|
||||||
Metablock* prev() const { return header()->_prev; }
|
|
||||||
void set_prev(Metablock* v) { _block._header._prev = v; }
|
|
||||||
|
|
||||||
static size_t min_block_byte_size() { return _min_block_byte_size; }
|
|
||||||
|
|
||||||
bool is_free() { return header()->_word_size != 0; }
|
|
||||||
void clear_next() { set_next(NULL); }
|
|
||||||
void link_prev(Metablock* ptr) { set_prev(ptr); }
|
|
||||||
uintptr_t* end() { return ((uintptr_t*) this) + size(); }
|
|
||||||
bool cantCoalesce() const { return false; }
|
|
||||||
void link_next(Metablock* ptr) { set_next(ptr); }
|
|
||||||
void link_after(Metablock* ptr){
|
|
||||||
link_next(ptr);
|
|
||||||
if (ptr != NULL) ptr->link_prev(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should not be needed in a free list of Metablocks
|
|
||||||
void markNotFree() { ShouldNotReachHere(); }
|
|
||||||
|
|
||||||
// Debug support
|
|
||||||
#ifdef ASSERT
|
|
||||||
void* prev_addr() const { return (void*)&_block._header._prev; }
|
|
||||||
void* next_addr() const { return (void*)&_block._header._next; }
|
|
||||||
void* size_addr() const { return (void*)&_block._header._word_size; }
|
|
||||||
#endif
|
|
||||||
bool verify_chunk_in_free_list(Metablock* tc) const { return true; }
|
|
||||||
bool verify_par_locked() { return true; }
|
|
||||||
|
|
||||||
void assert_is_mangled() const {/* Don't check "\*/}
|
|
||||||
};
|
|
||||||
#endif // SHARE_VM_MEMORY_METABLOCK_HPP
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -29,42 +29,32 @@
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
|
|
||||||
class VirtualSpaceNode;
|
class VirtualSpaceNode;
|
||||||
//
|
|
||||||
// Future modification
|
|
||||||
//
|
|
||||||
// The Metachunk can conceivable be replaced by the Chunk in
|
|
||||||
// allocation.hpp. Note that the latter Chunk is the space for
|
|
||||||
// allocation (allocations from the chunk are out of the space in
|
|
||||||
// the Chunk after the header for the Chunk) where as Metachunks
|
|
||||||
// point to space in a VirtualSpace. To replace Metachunks with
|
|
||||||
// Chunks, change Chunks so that they can be allocated out of a VirtualSpace.
|
|
||||||
|
|
||||||
const size_t metadata_chunk_initialize = 0xf7f7f7f7;
|
const size_t metadata_chunk_initialize = 0xf7f7f7f7;
|
||||||
|
|
||||||
size_t Metachunk::_overhead =
|
size_t Metachunk::object_alignment() {
|
||||||
Chunk::aligned_overhead_size(sizeof(Metachunk)) / BytesPerWord;
|
return ARENA_AMALLOC_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Metachunk::overhead() {
|
||||||
|
return align_size_up(sizeof(Metachunk), object_alignment()) / BytesPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
// Metachunk methods
|
// Metachunk methods
|
||||||
|
|
||||||
Metachunk::Metachunk(size_t word_size,
|
Metachunk::Metachunk(size_t word_size,
|
||||||
VirtualSpaceNode* container) :
|
VirtualSpaceNode* container)
|
||||||
_word_size(word_size),
|
: Metabase<Metachunk>(word_size),
|
||||||
_bottom(NULL),
|
|
||||||
_end(NULL),
|
|
||||||
_top(NULL),
|
_top(NULL),
|
||||||
_next(NULL),
|
|
||||||
_prev(NULL),
|
|
||||||
_container(container)
|
_container(container)
|
||||||
{
|
{
|
||||||
_bottom = (MetaWord*)this;
|
_top = initial_top();
|
||||||
_top = (MetaWord*)this + _overhead;
|
|
||||||
_end = (MetaWord*)this + word_size;
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
set_is_free(false);
|
set_is_tagged_free(false);
|
||||||
size_t data_word_size = pointer_delta(end(),
|
size_t data_word_size = pointer_delta(end(),
|
||||||
top(),
|
_top,
|
||||||
sizeof(MetaWord));
|
sizeof(MetaWord));
|
||||||
Copy::fill_to_words((HeapWord*) top(),
|
Copy::fill_to_words((HeapWord*)_top,
|
||||||
data_word_size,
|
data_word_size,
|
||||||
metadata_chunk_initialize);
|
metadata_chunk_initialize);
|
||||||
#endif
|
#endif
|
||||||
|
@ -82,22 +72,18 @@ 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() const {
|
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() const {
|
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() const {
|
|
||||||
return pointer_delta(_end, _bottom, sizeof(MetaWord));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metachunk::print_on(outputStream* st) const {
|
void Metachunk::print_on(outputStream* st) const {
|
||||||
st->print_cr("Metachunk:"
|
st->print_cr("Metachunk:"
|
||||||
" 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) {
|
if (Verbose) {
|
||||||
st->print_cr(" used " SIZE_FORMAT " free " SIZE_FORMAT,
|
st->print_cr(" used " SIZE_FORMAT " free " SIZE_FORMAT,
|
||||||
used_word_size(), free_word_size());
|
used_word_size(), free_word_size());
|
||||||
|
@ -109,8 +95,8 @@ void Metachunk::mangle() {
|
||||||
// Mangle the payload of the chunk and not the links that
|
// Mangle the payload of the chunk and not the links that
|
||||||
// maintain list of chunks.
|
// maintain list of chunks.
|
||||||
HeapWord* start = (HeapWord*)(bottom() + overhead());
|
HeapWord* start = (HeapWord*)(bottom() + overhead());
|
||||||
size_t word_size = capacity_word_size() - overhead();
|
size_t size = word_size() - overhead();
|
||||||
Copy::fill_to_words(start, word_size, metadata_chunk_initialize);
|
Copy::fill_to_words(start, size, metadata_chunk_initialize);
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
||||||
|
@ -118,9 +104,68 @@ void Metachunk::verify() {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Cannot walk through the blocks unless the blocks have
|
// Cannot walk through the blocks unless the blocks have
|
||||||
// headers with sizes.
|
// headers with sizes.
|
||||||
assert(_bottom <= _top &&
|
assert(bottom() <= _top &&
|
||||||
_top <= _end,
|
_top <= (MetaWord*)end(),
|
||||||
"Chunk has been smashed");
|
"Chunk has been smashed");
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////// Unit tests ///////////////
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
|
||||||
|
class TestMetachunk {
|
||||||
|
public:
|
||||||
|
static void test() {
|
||||||
|
size_t size = 2 * 1024 * 1024;
|
||||||
|
void* memory = malloc(size);
|
||||||
|
assert(memory != NULL, "Failed to malloc 2MB");
|
||||||
|
|
||||||
|
Metachunk* metachunk = ::new (memory) Metachunk(size / BytesPerWord, NULL);
|
||||||
|
|
||||||
|
assert(metachunk->bottom() == (MetaWord*)metachunk, "assert");
|
||||||
|
assert(metachunk->end() == (uintptr_t*)metachunk + metachunk->size(), "assert");
|
||||||
|
|
||||||
|
// Check sizes
|
||||||
|
assert(metachunk->size() == metachunk->word_size(), "assert");
|
||||||
|
assert(metachunk->word_size() == pointer_delta(metachunk->end(), metachunk->bottom(),
|
||||||
|
sizeof(MetaWord*)), "assert");
|
||||||
|
|
||||||
|
// Check usage
|
||||||
|
assert(metachunk->used_word_size() == metachunk->overhead(), "assert");
|
||||||
|
assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
|
||||||
|
assert(metachunk->top() == metachunk->initial_top(), "assert");
|
||||||
|
assert(metachunk->is_empty(), "assert");
|
||||||
|
|
||||||
|
// Allocate
|
||||||
|
size_t alloc_size = 64; // Words
|
||||||
|
assert(is_size_aligned(alloc_size, Metachunk::object_alignment()), "assert");
|
||||||
|
|
||||||
|
MetaWord* mem = metachunk->allocate(alloc_size);
|
||||||
|
|
||||||
|
// Check post alloc
|
||||||
|
assert(mem == metachunk->initial_top(), "assert");
|
||||||
|
assert(mem + alloc_size == metachunk->top(), "assert");
|
||||||
|
assert(metachunk->used_word_size() == metachunk->overhead() + alloc_size, "assert");
|
||||||
|
assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
|
||||||
|
assert(!metachunk->is_empty(), "assert");
|
||||||
|
|
||||||
|
// Clear chunk
|
||||||
|
metachunk->reset_empty();
|
||||||
|
|
||||||
|
// Check post clear
|
||||||
|
assert(metachunk->used_word_size() == metachunk->overhead(), "assert");
|
||||||
|
assert(metachunk->free_word_size() == metachunk->word_size() - metachunk->used_word_size(), "assert");
|
||||||
|
assert(metachunk->top() == metachunk->initial_top(), "assert");
|
||||||
|
assert(metachunk->is_empty(), "assert");
|
||||||
|
|
||||||
|
free(memory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void TestMetachunk_test() {
|
||||||
|
TestMetachunk::test();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,89 +24,44 @@
|
||||||
#ifndef SHARE_VM_MEMORY_METACHUNK_HPP
|
#ifndef SHARE_VM_MEMORY_METACHUNK_HPP
|
||||||
#define SHARE_VM_MEMORY_METACHUNK_HPP
|
#define SHARE_VM_MEMORY_METACHUNK_HPP
|
||||||
|
|
||||||
// Metachunk - Quantum of allocation from a Virtualspace
|
#include "memory/allocation.hpp"
|
||||||
// Metachunks are reused (when freed are put on a global freelist) and
|
#include "utilities/debug.hpp"
|
||||||
// have no permanent association to a SpaceManager.
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
// +--------------+ <- end
|
|
||||||
// | | --+ ---+
|
|
||||||
// | | | free |
|
|
||||||
// | | | |
|
|
||||||
// | | | | capacity
|
|
||||||
// | | | |
|
|
||||||
// | | <- top --+ |
|
|
||||||
// | | ---+ |
|
|
||||||
// | | | used |
|
|
||||||
// | | | |
|
|
||||||
// | | | |
|
|
||||||
// +--------------+ <- bottom ---+ ---+
|
|
||||||
|
|
||||||
class VirtualSpaceNode;
|
class VirtualSpaceNode;
|
||||||
|
|
||||||
class Metachunk VALUE_OBJ_CLASS_SPEC {
|
// Super class of Metablock and Metachunk to allow them to
|
||||||
// link to support lists of chunks
|
// be put on the FreeList and in the BinaryTreeDictionary.
|
||||||
Metachunk* _next;
|
template <class T>
|
||||||
Metachunk* _prev;
|
class Metabase VALUE_OBJ_CLASS_SPEC {
|
||||||
VirtualSpaceNode* _container;
|
|
||||||
|
|
||||||
MetaWord* _bottom;
|
|
||||||
MetaWord* _end;
|
|
||||||
MetaWord* _top;
|
|
||||||
size_t _word_size;
|
size_t _word_size;
|
||||||
// Used in a guarantee() so included in the Product builds
|
T* _next;
|
||||||
// even through it is only for debugging.
|
T* _prev;
|
||||||
bool _is_free;
|
|
||||||
|
|
||||||
// Metachunks are allocated out of a MetadataVirtualSpace and
|
protected:
|
||||||
// and use some of its space to describe itself (plus alignment
|
Metabase(size_t word_size) : _word_size(word_size), _next(NULL), _prev(NULL) {}
|
||||||
// considerations). Metadata is allocated in the rest of the chunk.
|
|
||||||
// This size is the overhead of maintaining the Metachunk within
|
|
||||||
// the space.
|
|
||||||
static size_t _overhead;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Metachunk(size_t word_size , VirtualSpaceNode* container);
|
T* next() const { return _next; }
|
||||||
|
T* prev() const { return _prev; }
|
||||||
|
void set_next(T* v) { _next = v; assert(v != this, "Boom");}
|
||||||
|
void set_prev(T* v) { _prev = v; assert(v != this, "Boom");}
|
||||||
|
void clear_next() { set_next(NULL); }
|
||||||
|
void clear_prev() { set_prev(NULL); }
|
||||||
|
|
||||||
// Used to add a Metachunk to a list of Metachunks
|
|
||||||
void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");}
|
|
||||||
void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");}
|
|
||||||
void set_container(VirtualSpaceNode* v) { _container = v; }
|
|
||||||
|
|
||||||
MetaWord* allocate(size_t word_size);
|
|
||||||
|
|
||||||
// Accessors
|
|
||||||
Metachunk* next() const { return _next; }
|
|
||||||
Metachunk* prev() const { return _prev; }
|
|
||||||
VirtualSpaceNode* container() const { return _container; }
|
|
||||||
MetaWord* bottom() const { return _bottom; }
|
|
||||||
MetaWord* end() const { return _end; }
|
|
||||||
MetaWord* top() const { return _top; }
|
|
||||||
size_t word_size() const { return _word_size; }
|
|
||||||
size_t size() const volatile { return _word_size; }
|
size_t size() const volatile { return _word_size; }
|
||||||
void set_size(size_t v) { _word_size = v; }
|
void set_size(size_t v) { _word_size = v; }
|
||||||
bool is_free() { return _is_free; }
|
|
||||||
void set_is_free(bool v) { _is_free = v; }
|
void link_next(T* ptr) { set_next(ptr); }
|
||||||
static size_t overhead() { return _overhead; }
|
void link_prev(T* ptr) { set_prev(ptr); }
|
||||||
void clear_next() { set_next(NULL); }
|
void link_after(T* ptr) {
|
||||||
void link_prev(Metachunk* ptr) { set_prev(ptr); }
|
|
||||||
uintptr_t* end() { return ((uintptr_t*) this) + size(); }
|
|
||||||
bool cantCoalesce() const { return false; }
|
|
||||||
void link_next(Metachunk* ptr) { set_next(ptr); }
|
|
||||||
void link_after(Metachunk* ptr){
|
|
||||||
link_next(ptr);
|
link_next(ptr);
|
||||||
if (ptr != NULL) ptr->link_prev(this);
|
if (ptr != NULL) ptr->link_prev((T*)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset top to bottom so chunk can be reused.
|
uintptr_t* end() const { return ((uintptr_t*) this) + size(); }
|
||||||
void reset_empty() { _top = (_bottom + _overhead); _next = NULL; _prev = NULL; }
|
|
||||||
bool is_empty() { return _top == (_bottom + _overhead); }
|
|
||||||
|
|
||||||
// used (has been allocated)
|
bool cantCoalesce() const { return false; }
|
||||||
// free (available for future allocations)
|
|
||||||
// capacity (total size of chunk)
|
|
||||||
size_t used_word_size() const;
|
|
||||||
size_t free_word_size() const;
|
|
||||||
size_t capacity_word_size()const;
|
|
||||||
|
|
||||||
// Debug support
|
// Debug support
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
|
@ -114,14 +69,98 @@ class Metachunk VALUE_OBJ_CLASS_SPEC {
|
||||||
void* next_addr() const { return (void*)&_next; }
|
void* next_addr() const { return (void*)&_next; }
|
||||||
void* size_addr() const { return (void*)&_word_size; }
|
void* size_addr() const { return (void*)&_word_size; }
|
||||||
#endif
|
#endif
|
||||||
bool verify_chunk_in_free_list(Metachunk* tc) const { return true; }
|
bool verify_chunk_in_free_list(T* tc) const { return true; }
|
||||||
bool verify_par_locked() { return true; }
|
bool verify_par_locked() { return true; }
|
||||||
|
|
||||||
void assert_is_mangled() const {/* Don't check "\*/}
|
void assert_is_mangled() const {/* Don't check "\*/}
|
||||||
|
|
||||||
NOT_PRODUCT(void mangle();)
|
bool is_free() { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Metachunk - Quantum of allocation from a Virtualspace
|
||||||
|
// Metachunks are reused (when freed are put on a global freelist) and
|
||||||
|
// have no permanent association to a SpaceManager.
|
||||||
|
|
||||||
|
// +--------------+ <- end --+ --+
|
||||||
|
// | | | |
|
||||||
|
// | | | free |
|
||||||
|
// | | | |
|
||||||
|
// | | | | size | capacity
|
||||||
|
// | | | |
|
||||||
|
// | | <- top -- + |
|
||||||
|
// | | | |
|
||||||
|
// | | | used |
|
||||||
|
// | | | |
|
||||||
|
// | | | |
|
||||||
|
// +--------------+ <- bottom --+ --+
|
||||||
|
|
||||||
|
class Metachunk : public Metabase<Metachunk> {
|
||||||
|
friend class TestMetachunk;
|
||||||
|
// The VirtualSpaceNode containing this chunk.
|
||||||
|
VirtualSpaceNode* _container;
|
||||||
|
|
||||||
|
// Current allocation top.
|
||||||
|
MetaWord* _top;
|
||||||
|
|
||||||
|
DEBUG_ONLY(bool _is_tagged_free;)
|
||||||
|
|
||||||
|
MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
|
||||||
|
MetaWord* top() const { return _top; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Metachunks are allocated out of a MetadataVirtualSpace and
|
||||||
|
// and use some of its space to describe itself (plus alignment
|
||||||
|
// considerations). Metadata is allocated in the rest of the chunk.
|
||||||
|
// This size is the overhead of maintaining the Metachunk within
|
||||||
|
// the space.
|
||||||
|
|
||||||
|
// Alignment of each allocation in the chunks.
|
||||||
|
static size_t object_alignment();
|
||||||
|
|
||||||
|
// Size of the Metachunk header, including alignment.
|
||||||
|
static size_t overhead();
|
||||||
|
|
||||||
|
Metachunk(size_t word_size , VirtualSpaceNode* container);
|
||||||
|
|
||||||
|
MetaWord* allocate(size_t word_size);
|
||||||
|
|
||||||
|
VirtualSpaceNode* container() const { return _container; }
|
||||||
|
|
||||||
|
MetaWord* bottom() const { return (MetaWord*) this; }
|
||||||
|
|
||||||
|
// Reset top to bottom so chunk can be reused.
|
||||||
|
void reset_empty() { _top = initial_top(); clear_next(); clear_prev(); }
|
||||||
|
bool is_empty() { return _top == initial_top(); }
|
||||||
|
|
||||||
|
// used (has been allocated)
|
||||||
|
// free (available for future allocations)
|
||||||
|
size_t word_size() const { return size(); }
|
||||||
|
size_t used_word_size() const;
|
||||||
|
size_t free_word_size() const;
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
void mangle();
|
||||||
|
bool is_tagged_free() { return _is_tagged_free; }
|
||||||
|
void set_is_tagged_free(bool v) { _is_tagged_free = v; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
void verify();
|
void verify();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Metablock is the unit of allocation from a Chunk.
|
||||||
|
//
|
||||||
|
// A Metablock may be reused by its SpaceManager but are never moved between
|
||||||
|
// SpaceManagers. There is no explicit link to the Metachunk
|
||||||
|
// from which it was allocated. Metablock may be deallocated and
|
||||||
|
// put on a freelist but the space is never freed, rather
|
||||||
|
// the Metachunk it is a part of will be deallocated when it's
|
||||||
|
// associated class loader is collected.
|
||||||
|
|
||||||
|
class Metablock : public Metabase<Metablock> {
|
||||||
|
friend class VMStructs;
|
||||||
|
public:
|
||||||
|
Metablock(size_t word_size) : Metabase<Metablock>(word_size) {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_MEMORY_METACHUNK_HPP
|
#endif // SHARE_VM_MEMORY_METACHUNK_HPP
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
#include "memory/freeList.hpp"
|
#include "memory/freeList.hpp"
|
||||||
#include "memory/gcLocker.hpp"
|
#include "memory/gcLocker.hpp"
|
||||||
#include "memory/metablock.hpp"
|
|
||||||
#include "memory/metachunk.hpp"
|
#include "memory/metachunk.hpp"
|
||||||
#include "memory/metaspace.hpp"
|
#include "memory/metaspace.hpp"
|
||||||
#include "memory/metaspaceShared.hpp"
|
#include "memory/metaspaceShared.hpp"
|
||||||
|
@ -49,8 +48,8 @@
|
||||||
|
|
||||||
typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
|
typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
|
||||||
typedef BinaryTreeDictionary<Metachunk, FreeList> ChunkTreeDictionary;
|
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;
|
const bool metaspace_slow_verify = false;
|
||||||
|
|
||||||
// Parameters for stress mode testing
|
// Parameters for stress mode testing
|
||||||
|
@ -92,24 +91,9 @@ volatile intptr_t MetaspaceGC::_capacity_until_GC = 0;
|
||||||
uint MetaspaceGC::_shrink_factor = 0;
|
uint MetaspaceGC::_shrink_factor = 0;
|
||||||
bool MetaspaceGC::_should_concurrent_collect = false;
|
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;
|
typedef class FreeList<Metachunk> ChunkList;
|
||||||
|
|
||||||
// Manages the global free lists of chunks.
|
// 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> {
|
class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
// Free list of chunks of different sizes.
|
// Free list of chunks of different sizes.
|
||||||
|
@ -119,7 +103,6 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
// HumongousChunk
|
// HumongousChunk
|
||||||
ChunkList _free_chunks[NumberOfFreeLists];
|
ChunkList _free_chunks[NumberOfFreeLists];
|
||||||
|
|
||||||
|
|
||||||
// HumongousChunk
|
// HumongousChunk
|
||||||
ChunkTreeDictionary _humongous_dictionary;
|
ChunkTreeDictionary _humongous_dictionary;
|
||||||
|
|
||||||
|
@ -230,7 +213,6 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
// to the allocation of a quantum of metadata).
|
// to the allocation of a quantum of metadata).
|
||||||
class BlockFreelist VALUE_OBJ_CLASS_SPEC {
|
class BlockFreelist VALUE_OBJ_CLASS_SPEC {
|
||||||
BlockTreeDictionary* _dictionary;
|
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
|
// Only allocate and split from freelist if the size of the allocation
|
||||||
// is at least 1/4th the size of the available block.
|
// 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;
|
void print_on(outputStream* st) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A VirtualSpaceList node.
|
||||||
class VirtualSpaceNode : public CHeapObj<mtClass> {
|
class VirtualSpaceNode : public CHeapObj<mtClass> {
|
||||||
friend class VirtualSpaceList;
|
friend class VirtualSpaceList;
|
||||||
|
|
||||||
|
@ -414,13 +397,13 @@ void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
|
||||||
Metachunk* chunk = first_chunk();
|
Metachunk* chunk = first_chunk();
|
||||||
Metachunk* invalid_chunk = (Metachunk*) top();
|
Metachunk* invalid_chunk = (Metachunk*) top();
|
||||||
while (chunk < invalid_chunk ) {
|
while (chunk < invalid_chunk ) {
|
||||||
assert(chunk->is_free(), "Should be marked free");
|
assert(chunk->is_tagged_free(), "Should be tagged free");
|
||||||
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
||||||
chunk_manager->remove_chunk(chunk);
|
chunk_manager->remove_chunk(chunk);
|
||||||
assert(chunk->next() == NULL &&
|
assert(chunk->next() == NULL &&
|
||||||
chunk->prev() == NULL,
|
chunk->prev() == NULL,
|
||||||
"Was not removed from its list");
|
"Was not removed from its list");
|
||||||
chunk = (Metachunk*) next;
|
chunk = (Metachunk*) next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +417,7 @@ uint VirtualSpaceNode::container_count_slow() {
|
||||||
// Don't count the chunks on the free lists. Those are
|
// Don't count the chunks on the free lists. Those are
|
||||||
// still part of the VirtualSpaceNode but not currently
|
// still part of the VirtualSpaceNode but not currently
|
||||||
// counted.
|
// counted.
|
||||||
if (!chunk->is_free()) {
|
if (!chunk->is_tagged_free()) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
chunk = (Metachunk*) next;
|
chunk = (Metachunk*) next;
|
||||||
|
@ -753,14 +736,11 @@ class SpaceManager : public CHeapObj<mtClass> {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t get_raw_word_size(size_t word_size) {
|
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 byte_size = word_size * BytesPerWord;
|
||||||
|
|
||||||
size_t raw_bytes_size = MAX2(byte_size,
|
size_t raw_bytes_size = MAX2(byte_size, sizeof(Metablock));
|
||||||
Metablock::min_block_byte_size());
|
raw_bytes_size = align_size_up(raw_bytes_size, Metachunk::object_alignment());
|
||||||
raw_bytes_size = ARENA_ALIGN(raw_bytes_size);
|
|
||||||
size_t raw_word_size = raw_bytes_size / BytesPerWord;
|
size_t raw_word_size = raw_bytes_size / BytesPerWord;
|
||||||
assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem");
|
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) {
|
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) {
|
if (dictionary() == NULL) {
|
||||||
_dictionary = new BlockTreeDictionary();
|
_dictionary = new BlockTreeDictionary();
|
||||||
}
|
}
|
||||||
|
@ -1069,7 +1040,7 @@ void ChunkManager::remove_chunk(Metachunk* chunk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chunk is being 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->word_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the list of VirtualSpaceNodes and delete
|
// Walk the list of VirtualSpaceNodes and delete
|
||||||
|
@ -1760,7 +1731,7 @@ void ChunkManager::free_chunks_put(Metachunk* chunk) {
|
||||||
chunk->set_next(free_list->head());
|
chunk->set_next(free_list->head());
|
||||||
free_list->set_head(chunk);
|
free_list->set_head(chunk);
|
||||||
// chunk is being returned to the chunk free list
|
// 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();
|
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.
|
// 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
|
// Remove it from the links to this freelist
|
||||||
chunk->set_next(NULL);
|
chunk->set_next(NULL);
|
||||||
|
@ -1830,7 +1801,7 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Chunk is no longer on any freelist. Setting to false make container_count_slow()
|
// Chunk is no longer on any freelist. Setting to false make container_count_slow()
|
||||||
// work.
|
// work.
|
||||||
chunk->set_is_free(false);
|
chunk->set_is_tagged_free(false);
|
||||||
#endif
|
#endif
|
||||||
chunk->container()->inc_container_count();
|
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)) {
|
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) {
|
||||||
sum += chunk->capacity_word_size();
|
sum += chunk->word_size();
|
||||||
chunk = chunk->next();
|
chunk = chunk->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2210,7 +2181,7 @@ void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) {
|
||||||
// Capture the next link before it is changed
|
// Capture the next link before it is changed
|
||||||
// by the call to return_chunk_at_head();
|
// by the call to return_chunk_at_head();
|
||||||
Metachunk* next = cur->next();
|
Metachunk* next = cur->next();
|
||||||
cur->set_is_free(true);
|
DEBUG_ONLY(cur->set_is_tagged_free(true);)
|
||||||
list->return_chunk_at_head(cur);
|
list->return_chunk_at_head(cur);
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
|
@ -2282,7 +2253,7 @@ SpaceManager::~SpaceManager() {
|
||||||
|
|
||||||
while (humongous_chunks != NULL) {
|
while (humongous_chunks != NULL) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
humongous_chunks->set_is_free(true);
|
humongous_chunks->set_is_tagged_free(true);
|
||||||
#endif
|
#endif
|
||||||
if (TraceMetadataChunkAllocation && Verbose) {
|
if (TraceMetadataChunkAllocation && Verbose) {
|
||||||
gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
|
gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ",
|
||||||
|
@ -2545,7 +2516,7 @@ void SpaceManager::dump(outputStream* const out) const {
|
||||||
curr->print_on(out);
|
curr->print_on(out);
|
||||||
curr_total += curr->word_size();
|
curr_total += curr->word_size();
|
||||||
used += curr->used_word_size();
|
used += curr->used_word_size();
|
||||||
capacity += curr->capacity_word_size();
|
capacity += curr->word_size();
|
||||||
waste += curr->free_word_size() + curr->overhead();;
|
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) {
|
bool read_only, MetaspaceObj::Type type, TRAPS) {
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
assert(false, "Should not allocate with exception pending");
|
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);
|
MetaWord* result = space->allocate(word_size, NonClassType);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite);
|
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;
|
MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;
|
||||||
|
@ -3443,7 +3418,10 @@ Metablock* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
|
||||||
return NULL;
|
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) {
|
void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) {
|
||||||
|
|
|
@ -139,7 +139,6 @@ class Metaspace : public CHeapObj<mtClass> {
|
||||||
// Allocate space for metadata of type mdtype. This is space
|
// Allocate space for metadata of type mdtype. This is space
|
||||||
// within a Metachunk and is used by
|
// within a Metachunk and is used by
|
||||||
// allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
|
// allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
|
||||||
// which returns a Metablock.
|
|
||||||
MetaWord* allocate(size_t word_size, MetadataType mdtype);
|
MetaWord* allocate(size_t word_size, MetadataType mdtype);
|
||||||
|
|
||||||
// Virtual Space lists for both classes and other metadata
|
// Virtual Space lists for both classes and other metadata
|
||||||
|
@ -217,8 +216,8 @@ class Metaspace : public CHeapObj<mtClass> {
|
||||||
size_t used_bytes_slow(MetadataType mdtype) const;
|
size_t used_bytes_slow(MetadataType mdtype) const;
|
||||||
size_t capacity_bytes_slow(MetadataType mdtype) const;
|
size_t capacity_bytes_slow(MetadataType mdtype) const;
|
||||||
|
|
||||||
static Metablock* allocate(ClassLoaderData* loader_data, size_t word_size,
|
static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size,
|
||||||
bool read_only, MetaspaceObj::Type type, TRAPS);
|
bool read_only, MetaspaceObj::Type type, TRAPS);
|
||||||
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
|
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
|
||||||
|
|
||||||
MetaWord* expand_and_allocate(size_t size,
|
MetaWord* expand_and_allocate(size_t size,
|
||||||
|
|
|
@ -5059,6 +5059,7 @@ void TestReservedSpace_test();
|
||||||
void TestReserveMemorySpecial_test();
|
void TestReserveMemorySpecial_test();
|
||||||
void TestVirtualSpace_test();
|
void TestVirtualSpace_test();
|
||||||
void TestMetaspaceAux_test();
|
void TestMetaspaceAux_test();
|
||||||
|
void TestMetachunk_test();
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
void TestG1BiasedArray_test();
|
void TestG1BiasedArray_test();
|
||||||
#endif
|
#endif
|
||||||
|
@ -5070,6 +5071,7 @@ void execute_internal_vm_tests() {
|
||||||
run_unit_test(TestReserveMemorySpecial_test());
|
run_unit_test(TestReserveMemorySpecial_test());
|
||||||
run_unit_test(TestVirtualSpace_test());
|
run_unit_test(TestVirtualSpace_test());
|
||||||
run_unit_test(TestMetaspaceAux_test());
|
run_unit_test(TestMetaspaceAux_test());
|
||||||
|
run_unit_test(TestMetachunk_test());
|
||||||
run_unit_test(GlobalDefinitions::test_globals());
|
run_unit_test(GlobalDefinitions::test_globals());
|
||||||
run_unit_test(GCTimerAllTest::all());
|
run_unit_test(GCTimerAllTest::all());
|
||||||
run_unit_test(arrayOopDesc::test_max_array_length());
|
run_unit_test(arrayOopDesc::test_max_array_length());
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
#include "memory/generation.hpp"
|
#include "memory/generation.hpp"
|
||||||
#include "memory/generationSpec.hpp"
|
#include "memory/generationSpec.hpp"
|
||||||
#include "memory/heap.hpp"
|
#include "memory/heap.hpp"
|
||||||
#include "memory/metablock.hpp"
|
#include "memory/metachunk.hpp"
|
||||||
#include "memory/referenceType.hpp"
|
#include "memory/referenceType.hpp"
|
||||||
#include "memory/space.hpp"
|
#include "memory/space.hpp"
|
||||||
#include "memory/tenuredGeneration.hpp"
|
#include "memory/tenuredGeneration.hpp"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue