Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/memory/metaspace/metaspaceArena.cpp
40957 views
1
/*
2
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 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
#include "precompiled.hpp"
27
#include "logging/log.hpp"
28
#include "logging/logStream.hpp"
29
#include "memory/metaspace/allocationGuard.hpp"
30
#include "memory/metaspace/chunkManager.hpp"
31
#include "memory/metaspace/counters.hpp"
32
#include "memory/metaspace/freeBlocks.hpp"
33
#include "memory/metaspace/internalStats.hpp"
34
#include "memory/metaspace/metachunk.hpp"
35
#include "memory/metaspace/metaspaceArena.hpp"
36
#include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
37
#include "memory/metaspace/metaspaceCommon.hpp"
38
#include "memory/metaspace/metaspaceSettings.hpp"
39
#include "memory/metaspace/metaspaceStatistics.hpp"
40
#include "memory/metaspace/virtualSpaceList.hpp"
41
#include "runtime/atomic.hpp"
42
#include "runtime/init.hpp"
43
#include "runtime/mutexLocker.hpp"
44
#include "services/memoryService.hpp"
45
#include "utilities/align.hpp"
46
#include "utilities/debug.hpp"
47
#include "utilities/globalDefinitions.hpp"
48
49
namespace metaspace {
50
51
#define LOGFMT "Arena @" PTR_FORMAT " (%s)"
52
#define LOGFMT_ARGS p2i(this), this->_name
53
54
// Returns the level of the next chunk to be added, acc to growth policy.
55
chunklevel_t MetaspaceArena::next_chunk_level() const {
56
const int growth_step = _chunks.count();
57
return _growth_policy->get_level_at_step(growth_step);
58
}
59
60
// Given a chunk, add its remaining free committed space to the free block list.
61
void MetaspaceArena::salvage_chunk(Metachunk* c) {
62
if (Settings::handle_deallocations() == false) {
63
return;
64
}
65
66
assert_lock_strong(lock());
67
size_t remaining_words = c->free_below_committed_words();
68
if (remaining_words > FreeBlocks::MinWordSize) {
69
70
UL2(trace, "salvaging chunk " METACHUNK_FULL_FORMAT ".", METACHUNK_FULL_FORMAT_ARGS(c));
71
72
MetaWord* ptr = c->allocate(remaining_words);
73
assert(ptr != NULL, "Should have worked");
74
_total_used_words_counter->increment_by(remaining_words);
75
76
add_allocation_to_fbl(ptr, remaining_words);
77
78
// After this operation: the chunk should have no free committed space left.
79
assert(c->free_below_committed_words() == 0,
80
"Salvaging chunk failed (chunk " METACHUNK_FULL_FORMAT ").",
81
METACHUNK_FULL_FORMAT_ARGS(c));
82
}
83
}
84
85
// Allocate a new chunk from the underlying chunk manager able to hold at least
86
// requested word size.
87
Metachunk* MetaspaceArena::allocate_new_chunk(size_t requested_word_size) {
88
assert_lock_strong(lock());
89
90
// Should this ever happen, we need to increase the maximum possible chunk size.
91
guarantee(requested_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE,
92
"Requested size too large (" SIZE_FORMAT ") - max allowed size per allocation is " SIZE_FORMAT ".",
93
requested_word_size, chunklevel::MAX_CHUNK_WORD_SIZE);
94
95
const chunklevel_t max_level = chunklevel::level_fitting_word_size(requested_word_size);
96
const chunklevel_t preferred_level = MIN2(max_level, next_chunk_level());
97
98
Metachunk* c = _chunk_manager->get_chunk(preferred_level, max_level, requested_word_size);
99
if (c == NULL) {
100
return NULL;
101
}
102
103
assert(c->is_in_use(), "Wrong chunk state.");
104
assert(c->free_below_committed_words() >= requested_word_size, "Chunk not committed");
105
return c;
106
}
107
108
void MetaspaceArena::add_allocation_to_fbl(MetaWord* p, size_t word_size) {
109
assert(Settings::handle_deallocations(), "Sanity");
110
if (_fbl == NULL) {
111
_fbl = new FreeBlocks(); // Create only on demand
112
}
113
_fbl->add_block(p, word_size);
114
}
115
116
MetaspaceArena::MetaspaceArena(ChunkManager* chunk_manager, const ArenaGrowthPolicy* growth_policy,
117
Mutex* lock, SizeAtomicCounter* total_used_words_counter,
118
const char* name) :
119
_lock(lock),
120
_chunk_manager(chunk_manager),
121
_growth_policy(growth_policy),
122
_chunks(),
123
_fbl(NULL),
124
_total_used_words_counter(total_used_words_counter),
125
_name(name)
126
{
127
UL(debug, ": born.");
128
129
// Update statistics
130
InternalStats::inc_num_arena_births();
131
}
132
133
MetaspaceArena::~MetaspaceArena() {
134
#ifdef ASSERT
135
verify();
136
if (Settings::use_allocation_guard()) {
137
verify_allocation_guards();
138
}
139
#endif
140
141
MutexLocker fcl(lock(), Mutex::_no_safepoint_check_flag);
142
MemRangeCounter return_counter;
143
144
Metachunk* c = _chunks.first();
145
Metachunk* c2 = NULL;
146
147
while (c) {
148
c2 = c->next();
149
return_counter.add(c->used_words());
150
DEBUG_ONLY(c->set_prev(NULL);)
151
DEBUG_ONLY(c->set_next(NULL);)
152
UL2(debug, "return chunk: " METACHUNK_FORMAT ".", METACHUNK_FORMAT_ARGS(c));
153
_chunk_manager->return_chunk(c);
154
// c may be invalid after return_chunk(c) was called. Don't access anymore.
155
c = c2;
156
}
157
158
UL2(info, "returned %d chunks, total capacity " SIZE_FORMAT " words.",
159
return_counter.count(), return_counter.total_size());
160
161
_total_used_words_counter->decrement_by(return_counter.total_size());
162
DEBUG_ONLY(chunk_manager()->verify();)
163
delete _fbl;
164
UL(debug, ": dies.");
165
166
// Update statistics
167
InternalStats::inc_num_arena_deaths();
168
}
169
170
// Attempt to enlarge the current chunk to make it large enough to hold at least
171
// requested_word_size additional words.
172
//
173
// On success, true is returned, false otherwise.
174
bool MetaspaceArena::attempt_enlarge_current_chunk(size_t requested_word_size) {
175
assert_lock_strong(lock());
176
177
Metachunk* c = current_chunk();
178
assert(c->free_words() < requested_word_size, "Sanity");
179
180
// Not if chunk enlargment is switched off...
181
if (Settings::enlarge_chunks_in_place() == false) {
182
return false;
183
}
184
// ... nor if we are already a root chunk ...
185
if (c->is_root_chunk()) {
186
return false;
187
}
188
// ... nor if the combined size of chunk content and new content would bring us above the size of a root chunk ...
189
if ((c->used_words() + requested_word_size) > metaspace::chunklevel::MAX_CHUNK_WORD_SIZE) {
190
return false;
191
}
192
193
const chunklevel_t new_level =
194
chunklevel::level_fitting_word_size(c->used_words() + requested_word_size);
195
assert(new_level < c->level(), "Sanity");
196
197
// Atm we only enlarge by one level (so, doubling the chunk in size). So, if the requested enlargement
198
// would require the chunk to more than double in size, we bail. But this covers about 99% of all cases,
199
// so this is good enough.
200
if (new_level < c->level() - 1) {
201
return false;
202
}
203
// This only works if chunk is the leader of its buddy pair (and also if buddy
204
// is free and unsplit, but that we cannot check outside of metaspace lock).
205
if (!c->is_leader()) {
206
return false;
207
}
208
// If the size added to the chunk would be larger than allowed for the next growth step
209
// dont enlarge.
210
if (next_chunk_level() > c->level()) {
211
return false;
212
}
213
214
bool success = _chunk_manager->attempt_enlarge_chunk(c);
215
assert(success == false || c->free_words() >= requested_word_size, "Sanity");
216
return success;
217
}
218
219
// Allocate memory from Metaspace.
220
// 1) Attempt to allocate from the free block list.
221
// 2) Attempt to allocate from the current chunk.
222
// 3) Attempt to enlarge the current chunk in place if it is too small.
223
// 4) Attempt to get a new chunk and allocate from that chunk.
224
// At any point, if we hit a commit limit, we return NULL.
225
MetaWord* MetaspaceArena::allocate(size_t requested_word_size) {
226
MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
227
UL2(trace, "requested " SIZE_FORMAT " words.", requested_word_size);
228
229
MetaWord* p = NULL;
230
const size_t raw_word_size = get_raw_word_size_for_requested_word_size(requested_word_size);
231
232
// 1) Attempt to allocate from the free blocks list
233
// (Note: to reduce complexity, deallocation handling is disabled if allocation guards
234
// are enabled, see Settings::ergo_initialize())
235
if (Settings::handle_deallocations() && _fbl != NULL && !_fbl->is_empty()) {
236
p = _fbl->remove_block(raw_word_size);
237
if (p != NULL) {
238
DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();)
239
UL2(trace, "taken from fbl (now: %d, " SIZE_FORMAT ").",
240
_fbl->count(), _fbl->total_size());
241
// Note: Space which is kept in the freeblock dictionary still counts as used as far
242
// as statistics go; therefore we skip the epilogue in this function to avoid double
243
// accounting.
244
return p;
245
}
246
}
247
248
bool current_chunk_too_small = false;
249
bool commit_failure = false;
250
251
if (current_chunk() != NULL) {
252
253
// 2) Attempt to satisfy the allocation from the current chunk.
254
255
// If the current chunk is too small to hold the requested size, attempt to enlarge it.
256
// If that fails, retire the chunk.
257
if (current_chunk()->free_words() < raw_word_size) {
258
if (!attempt_enlarge_current_chunk(raw_word_size)) {
259
current_chunk_too_small = true;
260
} else {
261
DEBUG_ONLY(InternalStats::inc_num_chunks_enlarged();)
262
UL(debug, "enlarged chunk.");
263
}
264
}
265
266
// Commit the chunk far enough to hold the requested word size. If that fails, we
267
// hit a limit (either GC threshold or MaxMetaspaceSize). In that case retire the
268
// chunk.
269
if (!current_chunk_too_small) {
270
if (!current_chunk()->ensure_committed_additional(raw_word_size)) {
271
UL2(info, "commit failure (requested size: " SIZE_FORMAT ")", raw_word_size);
272
commit_failure = true;
273
}
274
}
275
276
// Allocate from the current chunk. This should work now.
277
if (!current_chunk_too_small && !commit_failure) {
278
p = current_chunk()->allocate(raw_word_size);
279
assert(p != NULL, "Allocation from chunk failed.");
280
}
281
}
282
283
if (p == NULL) {
284
// If we are here, we either had no current chunk to begin with or it was deemed insufficient.
285
assert(current_chunk() == NULL ||
286
current_chunk_too_small || commit_failure, "Sanity");
287
288
Metachunk* new_chunk = allocate_new_chunk(raw_word_size);
289
if (new_chunk != NULL) {
290
UL2(debug, "allocated new chunk " METACHUNK_FORMAT " for requested word size " SIZE_FORMAT ".",
291
METACHUNK_FORMAT_ARGS(new_chunk), requested_word_size);
292
293
assert(new_chunk->free_below_committed_words() >= raw_word_size, "Sanity");
294
if (Settings::new_chunks_are_fully_committed()) {
295
assert(new_chunk->is_fully_committed(), "Chunk should be fully committed.");
296
}
297
298
// We have a new chunk. Before making it the current chunk, retire the old one.
299
if (current_chunk() != NULL) {
300
salvage_chunk(current_chunk());
301
DEBUG_ONLY(InternalStats::inc_num_chunks_retired();)
302
}
303
304
_chunks.add(new_chunk);
305
306
// Now, allocate from that chunk. That should work.
307
p = current_chunk()->allocate(raw_word_size);
308
assert(p != NULL, "Allocation from chunk failed.");
309
} else {
310
UL2(info, "failed to allocate new chunk for requested word size " SIZE_FORMAT ".", requested_word_size);
311
}
312
}
313
314
#ifdef ASSERT
315
// When using allocation guards, establish a prefix.
316
if (p != NULL && Settings::use_allocation_guard()) {
317
p = establish_prefix(p, raw_word_size);
318
}
319
#endif
320
321
if (p == NULL) {
322
InternalStats::inc_num_allocs_failed_limit();
323
} else {
324
DEBUG_ONLY(InternalStats::inc_num_allocs();)
325
_total_used_words_counter->increment_by(raw_word_size);
326
}
327
328
SOMETIMES(verify_locked();)
329
330
if (p == NULL) {
331
UL(info, "allocation failed, returned NULL.");
332
} else {
333
UL2(trace, "after allocation: %u chunk(s), current:" METACHUNK_FULL_FORMAT,
334
_chunks.count(), METACHUNK_FULL_FORMAT_ARGS(current_chunk()));
335
UL2(trace, "returning " PTR_FORMAT ".", p2i(p));
336
}
337
return p;
338
}
339
340
// Prematurely returns a metaspace allocation to the _block_freelists
341
// because it is not needed anymore (requires CLD lock to be active).
342
void MetaspaceArena::deallocate_locked(MetaWord* p, size_t word_size) {
343
if (Settings::handle_deallocations() == false) {
344
return;
345
}
346
347
assert_lock_strong(lock());
348
// At this point a current chunk must exist since we only deallocate if we did allocate before.
349
assert(current_chunk() != NULL, "stray deallocation?");
350
assert(is_valid_area(p, word_size),
351
"Pointer range not part of this Arena and cannot be deallocated: (" PTR_FORMAT ".." PTR_FORMAT ").",
352
p2i(p), p2i(p + word_size));
353
354
UL2(trace, "deallocating " PTR_FORMAT ", word size: " SIZE_FORMAT ".",
355
p2i(p), word_size);
356
357
size_t raw_word_size = get_raw_word_size_for_requested_word_size(word_size);
358
add_allocation_to_fbl(p, raw_word_size);
359
360
DEBUG_ONLY(verify_locked();)
361
}
362
363
// Prematurely returns a metaspace allocation to the _block_freelists because it is not
364
// needed anymore.
365
void MetaspaceArena::deallocate(MetaWord* p, size_t word_size) {
366
MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
367
deallocate_locked(p, word_size);
368
}
369
370
// Update statistics. This walks all in-use chunks.
371
void MetaspaceArena::add_to_statistics(ArenaStats* out) const {
372
MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
373
374
for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {
375
InUseChunkStats& ucs = out->_stats[c->level()];
376
ucs._num++;
377
ucs._word_size += c->word_size();
378
ucs._committed_words += c->committed_words();
379
ucs._used_words += c->used_words();
380
// Note: for free and waste, we only count what's committed.
381
if (c == current_chunk()) {
382
ucs._free_words += c->free_below_committed_words();
383
} else {
384
ucs._waste_words += c->free_below_committed_words();
385
}
386
}
387
388
if (_fbl != NULL) {
389
out->_free_blocks_num += _fbl->count();
390
out->_free_blocks_word_size += _fbl->total_size();
391
}
392
393
SOMETIMES(out->verify();)
394
}
395
396
// Convenience method to get the most important usage statistics.
397
// For deeper analysis use add_to_statistics().
398
void MetaspaceArena::usage_numbers(size_t* p_used_words, size_t* p_committed_words, size_t* p_capacity_words) const {
399
MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
400
size_t used = 0, comm = 0, cap = 0;
401
for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {
402
used += c->used_words();
403
comm += c->committed_words();
404
cap += c->word_size();
405
}
406
if (p_used_words != NULL) {
407
*p_used_words = used;
408
}
409
if (p_committed_words != NULL) {
410
*p_committed_words = comm;
411
}
412
if (p_capacity_words != NULL) {
413
*p_capacity_words = cap;
414
}
415
}
416
417
#ifdef ASSERT
418
419
void MetaspaceArena::verify_locked() const {
420
assert_lock_strong(lock());
421
assert(_growth_policy != NULL && _chunk_manager != NULL, "Sanity");
422
_chunks.verify();
423
if (_fbl != NULL) {
424
_fbl->verify();
425
}
426
}
427
428
void MetaspaceArena::verify_allocation_guards() const {
429
assert(Settings::use_allocation_guard(), "Don't call with guards disabled.");
430
431
// Verify canaries of all allocations.
432
// (We can walk all allocations since at the start of a chunk an allocation
433
// must be present, and the allocation header contains its size, so we can
434
// find the next one).
435
for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {
436
const Prefix* first_broken_block = NULL;
437
int num_broken_blocks = 0;
438
const MetaWord* p = c->base();
439
while (p < c->top()) {
440
const Prefix* pp = (const Prefix*)p;
441
if (!pp->is_valid()) {
442
UL2(error, "Corrupt block at " PTR_FORMAT " (chunk: " METACHUNK_FORMAT ").",
443
p2i(pp), METACHUNK_FORMAT_ARGS(c));
444
if (first_broken_block == NULL) {
445
first_broken_block = pp;
446
}
447
num_broken_blocks ++;
448
}
449
p += pp->_word_size;
450
}
451
// After examining all blocks in a chunk, assert if any of those blocks
452
// was found to be corrupted.
453
if (first_broken_block != NULL) {
454
assert(false, "Corrupt block: found at least %d corrupt metaspace block(s) - "
455
"first corrupted block at " PTR_FORMAT ".",
456
num_broken_blocks, p2i(first_broken_block));
457
}
458
}
459
}
460
461
void MetaspaceArena::verify() const {
462
MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
463
verify_locked();
464
}
465
466
// Returns true if the area indicated by pointer and size have actually been allocated
467
// from this arena.
468
bool MetaspaceArena::is_valid_area(MetaWord* p, size_t word_size) const {
469
assert(p != NULL && word_size > 0, "Sanity");
470
bool found = false;
471
for (const Metachunk* c = _chunks.first(); c != NULL && !found; c = c->next()) {
472
assert(c->is_valid_committed_pointer(p) ==
473
c->is_valid_committed_pointer(p + word_size - 1), "range intersects");
474
found = c->is_valid_committed_pointer(p);
475
}
476
return found;
477
}
478
479
#endif // ASSERT
480
481
void MetaspaceArena::print_on(outputStream* st) const {
482
MutexLocker fcl(_lock, Mutex::_no_safepoint_check_flag);
483
print_on_locked(st);
484
}
485
486
void MetaspaceArena::print_on_locked(outputStream* st) const {
487
assert_lock_strong(_lock);
488
st->print_cr("sm %s: %d chunks, total word size: " SIZE_FORMAT ", committed word size: " SIZE_FORMAT, _name,
489
_chunks.count(), _chunks.calc_word_size(), _chunks.calc_committed_word_size());
490
_chunks.print_on(st);
491
st->cr();
492
st->print_cr("growth-policy " PTR_FORMAT ", lock " PTR_FORMAT ", cm " PTR_FORMAT ", fbl " PTR_FORMAT,
493
p2i(_growth_policy), p2i(_lock), p2i(_chunk_manager), p2i(_fbl));
494
}
495
496
} // namespace metaspace
497
498
499