101 "Requested size too large (" SIZE_FORMAT ") - max allowed size per allocation is " SIZE_FORMAT ".", |
101 "Requested size too large (" SIZE_FORMAT ") - max allowed size per allocation is " SIZE_FORMAT ".", |
102 requested_word_size, chklvl::MAX_CHUNK_WORD_SIZE); |
102 requested_word_size, chklvl::MAX_CHUNK_WORD_SIZE); |
103 |
103 |
104 // If we have a current chunk, it should have been retired (almost empty) beforehand. |
104 // If we have a current chunk, it should have been retired (almost empty) beforehand. |
105 // See: retire_current_chunk(). |
105 // See: retire_current_chunk(). |
106 assert(current_chunk() == NULL || current_chunk()->free_below_committed_words() <= 10, "Must retire chunk beforehand"); |
106 assert(current_chunk() == NULL || |
|
107 (_is_micro_loader || current_chunk()->free_below_committed_words() <= 10), "Must retire chunk beforehand"); |
107 |
108 |
108 const chklvl_t min_level = chklvl::level_fitting_word_size(requested_word_size); |
109 const chklvl_t min_level = chklvl::level_fitting_word_size(requested_word_size); |
109 chklvl_t pref_level = _chunk_alloc_sequence->get_next_chunk_level(_chunks.size()); |
110 chklvl_t pref_level = _chunk_alloc_sequence->get_next_chunk_level(_chunks.size()); |
110 |
111 |
111 if (pref_level > min_level) { |
112 if (pref_level > min_level) { |
157 |
158 |
158 SpaceManager::SpaceManager(ChunkManager* chunk_manager, |
159 SpaceManager::SpaceManager(ChunkManager* chunk_manager, |
159 const ChunkAllocSequence* alloc_sequence, |
160 const ChunkAllocSequence* alloc_sequence, |
160 Mutex* lock, |
161 Mutex* lock, |
161 SizeAtomicCounter* total_used_words_counter, |
162 SizeAtomicCounter* total_used_words_counter, |
162 const char* name) |
163 const char* name, |
|
164 bool is_micro_loader) |
163 : _lock(lock), |
165 : _lock(lock), |
164 _chunk_manager(chunk_manager), |
166 _chunk_manager(chunk_manager), |
165 _chunk_alloc_sequence(alloc_sequence), |
167 _chunk_alloc_sequence(alloc_sequence), |
166 _chunks(), |
168 _chunks(), |
167 _block_freelist(NULL), |
169 _block_freelist(NULL), |
168 _total_used_words_counter(total_used_words_counter), |
170 _total_used_words_counter(total_used_words_counter), |
169 _name(name) |
171 _name(name), |
|
172 _is_micro_loader(is_micro_loader) |
170 { |
173 { |
171 } |
174 } |
172 |
175 |
173 SpaceManager::~SpaceManager() { |
176 SpaceManager::~SpaceManager() { |
174 |
177 |
205 // But since these cases should be exceedingly rare, we do not handle them special in order to keep |
208 // But since these cases should be exceedingly rare, we do not handle them special in order to keep |
206 // the code simple. |
209 // the code simple. |
207 |
210 |
208 size_t raw_remaining_words = c->free_below_committed_words(); |
211 size_t raw_remaining_words = c->free_below_committed_words(); |
209 size_t net_remaining_words = get_net_allocation_word_size(raw_remaining_words); |
212 size_t net_remaining_words = get_net_allocation_word_size(raw_remaining_words); |
210 if (net_remaining_words > 0) { |
213 |
|
214 // Note: Micro class loaders (lambdas, reflection) are typically the vast majority of loaders. They |
|
215 // will typically only once - if at all - ever retire a chunk, and the remaining size is typically |
|
216 // very small. |
|
217 // That means that the structure needed to manage this left over space will not see much action. However, |
|
218 // that structure is expensive as well (pointer lists) and therefore we only should generate it if the |
|
219 // benefit of managing free space out-weights the costs for that structure. |
|
220 // Non-micro loaders may continue loading, deallocating and retiring more chunks, so the cost of that |
|
221 // structure may amortize over time. But micro loaders probably never will. |
|
222 const size_t dont_bother_below_word_size = _is_micro_loader ? 64 : 0; |
|
223 |
|
224 if (net_remaining_words > dont_bother_below_word_size) { |
211 |
225 |
212 log_debug(metaspace)(LOGFMT_SPCMGR " @" PTR_FORMAT " : retiring chunk " METACHUNK_FULL_FORMAT ".", |
226 log_debug(metaspace)(LOGFMT_SPCMGR " @" PTR_FORMAT " : retiring chunk " METACHUNK_FULL_FORMAT ".", |
213 LOGFMT_SPCMGR_ARGS, p2i(this), METACHUNK_FULL_FORMAT_ARGS(c)); |
227 LOGFMT_SPCMGR_ARGS, p2i(this), METACHUNK_FULL_FORMAT_ARGS(c)); |
214 |
228 |
215 bool did_hit_limit = false; |
229 bool did_hit_limit = false; |
223 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
237 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
224 METACHUNK_FULL_FORMAT_ARGS(current_chunk())); |
238 METACHUNK_FULL_FORMAT_ARGS(current_chunk())); |
225 |
239 |
226 DEBUG_ONLY(verify_locked();) |
240 DEBUG_ONLY(verify_locked();) |
227 |
241 |
|
242 DEBUG_ONLY(InternalStats::inc_num_chunks_retired();) |
228 } |
243 } |
229 |
244 |
230 } |
245 } |
231 |
246 |
232 // Allocate memory from Metaspace. |
247 // Allocate memory from Metaspace. |
332 |
347 |
333 // Before we allocate a new chunk we need to retire the old chunk, which is too small to serve our request |
348 // Before we allocate a new chunk we need to retire the old chunk, which is too small to serve our request |
334 // but may still have free committed words. |
349 // but may still have free committed words. |
335 retire_current_chunk(); |
350 retire_current_chunk(); |
336 |
351 |
337 DEBUG_ONLY(InternalStats::inc_num_chunks_retired();) |
|
338 |
|
339 // Allocate a new chunk. |
352 // Allocate a new chunk. |
340 if (allocate_new_current_chunk(raw_word_size) == false) { |
353 if (allocate_new_current_chunk(raw_word_size) == false) { |
341 did_hit_limit = true; |
354 did_hit_limit = true; |
342 } else { |
355 } else { |
343 assert(current_chunk() != NULL && current_chunk()->free_words() >= raw_word_size, "Sanity"); |
356 assert(current_chunk() != NULL && current_chunk()->free_words() >= raw_word_size, "Sanity"); |