Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/memory/metaspace/metachunk.hpp
40957 views
1
/*
2
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2017, 2020 SAP SE. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*
24
*/
25
26
#ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
27
#define SHARE_MEMORY_METASPACE_METACHUNK_HPP
28
29
#include "memory/metaspace/chunklevel.hpp"
30
#include "memory/metaspace/counters.hpp"
31
#include "utilities/debug.hpp"
32
#include "utilities/globalDefinitions.hpp"
33
34
class outputStream;
35
36
namespace metaspace {
37
38
class VirtualSpaceNode;
39
40
// A Metachunk is a contiguous metaspace memory region. It is used by
41
// a MetaspaceArena to allocate from via pointer bump (somewhat similar
42
// to a TLAB in java heap.
43
//
44
// The Metachunk object itself (the "chunk header") is separated from
45
// the memory region (the chunk payload) it describes. It also can have
46
// no payload (a "dead" chunk). In itself it lives in C-heap, managed
47
// as part of a pool of Metachunk headers (ChunkHeaderPool).
48
//
49
//
50
// +---------+ +---------+ +---------+
51
// |MetaChunk| <--next/prev--> |MetaChunk| <--next/prev--> |MetaChunk| Chunk headers
52
// +---------+ +---------+ +---------+ in C-heap
53
// | | |
54
// base base base
55
// | / |
56
// / --------------- /
57
// / / ----------------------------
58
// | | /
59
// v v v
60
// +---------+ +---------+ +-------------------+
61
// | | | | | |
62
// | chunk | | chunk | | chunk | The real chunks ("payload")
63
// | | | | | | live in Metaspace
64
// +---------+ +---------+ +-------------------+
65
//
66
//
67
// -- Metachunk state --
68
//
69
// A Metachunk is "in-use" if it is part of a MetaspaceArena. That means
70
// its memory is used - or will be used shortly - to hold VM metadata
71
// on behalf of a class loader.
72
//
73
// A Metachunk is "free" if its payload is currently unused. In that
74
// case it is managed by a chunk freelist (the ChunkManager).
75
//
76
// A Metachunk is "dead" if it does not have a corresponding payload.
77
// In that case it lives as part of a freelist-of-dead-chunk-headers
78
// in the ChunkHeaderPool.
79
//
80
// A Metachunk is always part of a linked list. In-use chunks are part of
81
// the chunk list of a MetaspaceArena. Free chunks are in a freelist in
82
// the ChunkManager. Dead chunk headers are in a linked list as part
83
// of the ChunkHeaderPool.
84
//
85
//
86
// -- Level --
87
//
88
// Metachunks are managed as part of a buddy style allocation scheme.
89
// Sized always in steps of power-of-2, ranging from the smallest chunk size
90
// (1Kb) to the largest (4Mb) (see chunklevel.hpp).
91
// Its size is encoded as level, with level 0 being the largest chunk
92
// size ("root chunk").
93
//
94
//
95
// -- Payload commit state --
96
//
97
// A Metachunk payload (the "real chunk") may be committed, partly committed
98
// or completely uncommitted. Technically, a payload may be committed
99
// "checkered" - i.e. committed and uncommitted parts may interleave - but the
100
// important part is how much contiguous space is committed starting
101
// at the base of the payload (since that's where we allocate).
102
//
103
// The Metachunk keeps track of how much space is committed starting
104
// at the base of the payload - which is a performace optimization -
105
// while underlying layers (VirtualSpaceNode->commitmask) keep track
106
// of the "real" commit state, aka which granules are committed,
107
// independent on what chunks reside above those granules.
108
109
// +--------------+ <- end -----------+ ----------+
110
// | | | |
111
// | | | |
112
// | | | |
113
// | | | |
114
// | | | |
115
// | ----------- | <- committed_top -- + |
116
// | | | |
117
// | | | "free" |
118
// | | | | size
119
// | | "free_below_ | |
120
// | | committed" | |
121
// | | | |
122
// | | | |
123
// | ----------- | <- top --------- + -------- |
124
// | | | |
125
// | | "used" | |
126
// | | | |
127
// +--------------+ <- start ----------+ ----------+
128
//
129
//
130
// -- Relationships --
131
//
132
// Chunks are managed by a binary buddy style allocator
133
// (see https://en.wikipedia.org/wiki/Buddy_memory_allocation).
134
// Chunks which are not a root chunk always have an adjoining buddy.
135
// The first chunk in a buddy pair is called the leader, the second
136
// one the follower.
137
//
138
// +----------+----------+
139
// | leader | follower |
140
// +----------+----------+
141
//
142
//
143
// -- Layout in address space --
144
//
145
// In order to implement buddy style allocation, we need an easy way to get
146
// from one chunk to the Metachunk representing the neighboring chunks
147
// (preceding resp. following it in memory).
148
// But Metachunk headers and chunks are physically separated, and it is not
149
// possible to get the Metachunk* from the start of the chunk. Therefore
150
// Metachunk headers are part of a second linked list, describing the order
151
// in which their payload appears in memory:
152
//
153
// +---------+ +---------+ +---------+
154
// |MetaChunk| <--next/prev_in_vs--> |MetaChunk| <--next/prev_in_vs--> |MetaChunk|
155
// +---------+ +---------+ +---------+
156
// | | |
157
// base base base
158
// | / |
159
// / -------------------------- /
160
// / / --------------------------------------------------
161
// | | /
162
// v v v
163
// +---------+---------+-------------------+
164
// | chunk | chunk | chunk |
165
// +---------+---------+-------------------+
166
//
167
168
class Metachunk {
169
170
// start of chunk memory; NULL if dead.
171
MetaWord* _base;
172
173
// Used words.
174
size_t _used_words;
175
176
// Size of the region, starting from base, which is guaranteed to be committed. In words.
177
// The actual size of committed regions may actually be larger.
178
//
179
// (This is a performance optimization. The underlying VirtualSpaceNode knows
180
// which granules are committed; but we want to avoid having to ask.)
181
size_t _committed_words;
182
183
chunklevel_t _level; // aka size.
184
185
// state_free: free, owned by a ChunkManager
186
// state_in_use: in-use, owned by a MetaspaceArena
187
// dead: just a hollow chunk header without associated memory, owned
188
// by chunk header pool.
189
enum class State : uint8_t {
190
Free = 0,
191
InUse = 1,
192
Dead = 2
193
};
194
State _state;
195
196
// We need unfortunately a back link to the virtual space node
197
// for splitting and merging nodes.
198
VirtualSpaceNode* _vsnode;
199
200
// A chunk header is kept in a list:
201
// 1 in the list of used chunks inside a MetaspaceArena, if it is in use
202
// 2 in the list of free chunks inside a ChunkManager, if it is free
203
// 3 in the freelist of unused headers inside the ChunkHeaderPool,
204
// if it is unused (e.g. result of chunk merging) and has no associated
205
// memory area.
206
Metachunk* _prev;
207
Metachunk* _next;
208
209
// Furthermore, we keep, per chunk, information about the neighboring chunks.
210
// This is needed to split and merge chunks.
211
//
212
// Note: These members can be modified concurrently while a chunk is alive and in use.
213
// This can happen if a neighboring chunk is added or removed.
214
// This means only read or modify these members under expand lock protection.
215
Metachunk* _prev_in_vs;
216
Metachunk* _next_in_vs;
217
218
// Commit uncommitted section of the chunk.
219
// Fails if we hit a commit limit.
220
bool commit_up_to(size_t new_committed_words);
221
222
DEBUG_ONLY(static void assert_have_expand_lock();)
223
224
public:
225
226
Metachunk() :
227
_base(NULL),
228
_used_words(0),
229
_committed_words(0),
230
_level(chunklevel::ROOT_CHUNK_LEVEL),
231
_state(State::Free),
232
_vsnode(NULL),
233
_prev(NULL), _next(NULL),
234
_prev_in_vs(NULL),
235
_next_in_vs(NULL)
236
{}
237
238
void clear() {
239
_base = NULL;
240
_used_words = 0; _committed_words = 0;
241
_level = chunklevel::ROOT_CHUNK_LEVEL;
242
_state = State::Free;
243
_vsnode = NULL;
244
_prev = NULL; _next = NULL;
245
_prev_in_vs = NULL; _next_in_vs = NULL;
246
}
247
248
size_t word_size() const { return chunklevel::word_size_for_level(_level); }
249
250
MetaWord* base() const { return _base; }
251
MetaWord* top() const { return base() + _used_words; }
252
MetaWord* committed_top() const { return base() + _committed_words; }
253
MetaWord* end() const { return base() + word_size(); }
254
255
// Chunk list wiring
256
void set_prev(Metachunk* c) { _prev = c; }
257
Metachunk* prev() const { return _prev; }
258
void set_next(Metachunk* c) { _next = c; }
259
Metachunk* next() const { return _next; }
260
261
DEBUG_ONLY(bool in_list() const { return _prev != NULL || _next != NULL; })
262
263
// Physical neighbors wiring
264
void set_prev_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _prev_in_vs = c; }
265
Metachunk* prev_in_vs() const { DEBUG_ONLY(assert_have_expand_lock()); return _prev_in_vs; }
266
void set_next_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _next_in_vs = c; }
267
Metachunk* next_in_vs() const { DEBUG_ONLY(assert_have_expand_lock()); return _next_in_vs; }
268
269
bool is_free() const { return _state == State::Free; }
270
bool is_in_use() const { return _state == State::InUse; }
271
bool is_dead() const { return _state == State::Dead; }
272
void set_free() { _state = State::Free; }
273
void set_in_use() { _state = State::InUse; }
274
void set_dead() { _state = State::Dead; }
275
276
// Return a single char presentation of the state ('f', 'u', 'd')
277
char get_state_char() const;
278
279
void inc_level() { _level++; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
280
void dec_level() { _level --; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
281
chunklevel_t level() const { return _level; }
282
283
// Convenience functions for extreme levels.
284
bool is_root_chunk() const { return chunklevel::ROOT_CHUNK_LEVEL == _level; }
285
bool is_leaf_chunk() const { return chunklevel::HIGHEST_CHUNK_LEVEL == _level; }
286
287
VirtualSpaceNode* vsnode() const { return _vsnode; }
288
289
size_t used_words() const { return _used_words; }
290
size_t free_words() const { return word_size() - used_words(); }
291
size_t free_below_committed_words() const { return committed_words() - used_words(); }
292
void reset_used_words() { _used_words = 0; }
293
294
size_t committed_words() const { return _committed_words; }
295
void set_committed_words(size_t v);
296
bool is_fully_committed() const { return committed_words() == word_size(); }
297
bool is_fully_uncommitted() const { return committed_words() == 0; }
298
299
// Ensure that chunk is committed up to at least new_committed_words words.
300
// Fails if we hit a commit limit.
301
bool ensure_committed(size_t new_committed_words);
302
bool ensure_committed_locked(size_t new_committed_words);
303
304
// Ensure that the chunk is committed far enough to serve an additional allocation of word_size.
305
bool ensure_committed_additional(size_t additional_word_size) {
306
return ensure_committed(used_words() + additional_word_size);
307
}
308
309
// Uncommit chunk area. The area must be a common multiple of the
310
// commit granule size (in other words, we cannot uncommit chunks smaller than
311
// a commit granule size).
312
void uncommit();
313
void uncommit_locked();
314
315
// Allocation from a chunk
316
317
// Allocate word_size words from this chunk (word_size must be aligned to
318
// allocation_alignment_words).
319
//
320
// Caller must make sure the chunk is both large enough and committed far enough
321
// to hold the allocation. Will always work.
322
//
323
MetaWord* allocate(size_t request_word_size);
324
325
// Initialize structure for reuse.
326
void initialize(VirtualSpaceNode* node, MetaWord* base, chunklevel_t lvl) {
327
clear();
328
_vsnode = node; _base = base; _level = lvl;
329
}
330
331
// Returns true if this chunk is the leader in its buddy pair, false if not.
332
// Do not call for root chunks.
333
bool is_leader() const {
334
assert(!is_root_chunk(), "Root chunks have no buddy."); // Bit harsh?
335
return is_aligned(base(), chunklevel::word_size_for_level(level() - 1) * BytesPerWord);
336
}
337
338
//// Debug stuff ////
339
#ifdef ASSERT
340
void verify() const;
341
// Verifies linking with neighbors in virtual space. Needs expand lock protection.
342
void verify_neighborhood() const;
343
void zap_header(uint8_t c = 0x17);
344
345
// Returns true if given pointer points into the payload area of this chunk.
346
bool is_valid_pointer(const MetaWord* p) const {
347
return base() <= p && p < top();
348
}
349
350
// Returns true if given pointer points into the commmitted payload area of this chunk.
351
bool is_valid_committed_pointer(const MetaWord* p) const {
352
return base() <= p && p < committed_top();
353
}
354
355
#endif // ASSERT
356
357
void print_on(outputStream* st) const;
358
359
};
360
361
// Little print helpers: since we often print out chunks, here some convenience macros
362
#define METACHUNK_FORMAT "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT
363
#define METACHUNK_FORMAT_ARGS(chunk) p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level()
364
365
#define METACHUNK_FULL_FORMAT "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT " (" SIZE_FORMAT "), used: " SIZE_FORMAT ", committed: " SIZE_FORMAT ", committed-free: " SIZE_FORMAT
366
#define METACHUNK_FULL_FORMAT_ARGS(chunk) p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level(), chunk->word_size(), chunk->used_words(), chunk->committed_words(), chunk->free_below_committed_words()
367
368
} // namespace metaspace
369
370
#endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
371
372