...
With compressed class space enabled, we have two Metaspace contexts (one normal, one wrapping the class space), and each CLD has now two arenas, one associated with non-class context, one with the class space.
In this mode, memory for Klass
structures is allocated from the class space, all other metaspace allocations from the non-class metaspace:
+--------+ +--------+
| CLD | | CLD |
+--------+ +--------+
/ \ / \ Each CLD has two arenas...
/ \ / \
/ \ / \
v v v v
+--------+ +--------+ +--------+ +--------+
| noncl | | class | | noncl | | class |
| arena | | arena | | arena | | arena |
+--------+ +--------+ +--------+ +--------+
| \ / |
| --------\ | Non-class arenas take from non-class context,
| / | | class arenas take from class context
| /--------- | |
v v v v
+--------------------+ +------------------------+
| | | |
| Metaspace Context | | Metaspace Context |
| (nonclass) | | (class) |
| | | |
+--------------------+ +------------------------+
| | |
| | | Non-class context: list of smallish mappings
| | | Class context: one large mapping (the class space)
v v v
+--------+ +--------+ +----------------~~~~~~~-----+
| | | | | |
| virtual| | virt | | virt space (class space) |
| space | | space | | |
| | | | | |
+--------+ +--------+ +----------------~~~~~~~-----+
...
It is responsible for reserving and committing memory. It knows about commit granules. Its outside interface to upper layers is the VirtualSpaceList
while some operations are also directly exposed via VirtualSpaceNode.
...
Essential operations
"Allocate new root chunk"
Metachunk* VirtualSpaceList::allocate_root_chunk();
This carves out a new root chunk from the underlying reserved space and hands it to the caller (nothing is committed yet, this is purely reserved memory).
"commit this range"
bool VirtualSpaceNode::ensure_range_is_committed(MetaWord* p, size_t word_size);
Upper layers request that a given arbitrary address range should be committed. Subsystem figures out which granules would be affected and makes sure those are committed (which may be a noop if they had been committed before).
When committing, subsystem honors VM limits (
MaxMetaspaceSize
resp. the commit gc threshold) via the commit limiter."uncommit this range"
void VirtualSpaceNode::uncommit_range(MetaWord* p, size_t word_size);
Similar to committing. Subsystem figures out which commit granules are affected, and uncommits those.
"purge"
void VirtualSpaceList::purge()
This unmaps all completely empty memory regions, and uncommits all unused commit granules.
...
Other operations
The Virtual Memory Subsystem takes care of Buddy Allocator operations, on behalf of upper regions:
- "split this chunk, recursivly"
void VirtualSpaceNode::split(chunklevel_t target_level, Metachunk* c, FreeChunkListVector* freelists);
- "merge up chunk with neighbors as far as possible"
-
Metachunk* VirtualSpaceNode::merge(Metachunk* c, FreeChunkListVector* freelists);
- "enlarge chunk in place"
bool VirtualSpaceNode::attempt_enlarge_chunk(Metachunk* c, FreeChunkListVector* freelists);
...
Classes
...
VirtualSpaceList
VirtualSpaceList
is (virtualSpaceList.hpp) encapsulates a list of reserved regions memory mappings (instances of VirtualSpaceNode
). VirtualSpaceList manages a single (if non-expandable) or a series of (if expandable) virtual memory regions.
Internally it holds a list of nodes (VirtualSpaceNode), each one managing a single contiguous memory region. The first node of this list is the current node and used for allocation of new root chunks.
Beyond access to those nodes, and the ability to grow new nodes (if expandable), it allows for purging: purging this list means removing and unmapping all memory regions which are unused. Other than that, this class is unexciting.
Of this object only exist one or two global instances, contained within the one or two MetaspaceContext
values which exist globally.
2.1.3.2. class VirtualSpaceNode
VirtualSpaceNode
manages one contiguous reserved region of the Metaspace.
This list can be expandable - new mappings can be added on demand - or non-expandable.
The non-expandable latter case is used to represent the class space, which has to be a single contiguous address range for compressed Klass* pointer encoding to work. In that case, the class-space VirtualSpaceList just contains a single node, which wraps the whole of the class space. This may sound complicated but is just a matter of code reuse.
VirtualSpaceNode
VirtualSpaceNode
manages one contiguous memory mapping for Metaspace. In case of the compressed class space, it contains this encompasses the whole compressed class space, contained in a list with a single node which cannot be expanded.pre-reserved address range of the class space. In case of the non-class metaspace, these are smallish mappings, by default two root chunks in size.
VirtualSpaceNode knows about commit granules, and it knows which commit granules in it are commited (via the commit maskIt knows which granules in this region are committed (class CommitMask
).
VirtualSpaceNode also knows about root chunks: the its memory is divided into a series of root-chunk-sized areas (class RootChunkArea
). This means the memory has To keep coding simple, we require each memory mapping to be aligned (both starting address and size) to root chunk area size of 4M.to root chunk size in both start address and size.
Note: the concepts of chunks and of commit granules are almost completely independent from each other. The former is a means of handing out/taking back memory while avoiding fragmentation; the latter a way to manage commit state of memory.
Putting this all together, the memory underlying a VirtualSpaceNode looks like this:
base end
| | root chunk | root chunk | root chunk |
+-----------------------------------------------------+
| |
v |
| `VirtualSpaceNode` memory |
| v
| root chunk area | root chunk area | root chunk area | root chunk area |
|x| |
+-----------------------------------------------------+
|x|x|x|x| | | | |x|x|x| | | | |x|x|x | | |x| x|x|x| | | | | |x|x |x|x | | | | <-- commit granules
(x = committed)
Note: the concepts of commit granules and of root chunks and the buddy allocator are almost completely independent from each other.
...
CommitMask
Very unexciting. Just a bit mask inside a VirtualSpaceNode holding commit information (one bit per granule).
...
RootChunkArea and
...
RootChunkAreaLUT
RootChunkArea
contains the buddy allocator code. It is wrapped over the area of a single root chunk.
It knows how to split and merge chunks. It also has a reference to the very first chunk in this area (needed since Metachunk
chunk headers are separate entities from their payload, see below, and it is not easy to get from the metaspace start address to its Metachunk
).
...
RootChunkAreaLUT
(for "lookup table") just holds the sequence of RootChunkArea
classes which cover the memory region of the VirtualSpaceNode
. It offers lookup functionality "give me the RootChunkArea
for this address".
2.1.3.5. class CommitLimiter
...