24 */ |
24 */ |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
26 |
26 |
27 #include "logging/log.hpp" |
27 #include "logging/log.hpp" |
28 #include "logging/logStream.hpp" |
28 #include "logging/logStream.hpp" |
|
29 #include "memory/metaspace/blockFreelist.hpp" |
29 #include "memory/metaspace/chunkManager.hpp" |
30 #include "memory/metaspace/chunkManager.hpp" |
30 #include "memory/metaspace/internStat.hpp" |
31 #include "memory/metaspace/internStat.hpp" |
|
32 #include "memory/metaspace/leftOverBins.inline.hpp" |
31 #include "memory/metaspace/metachunk.hpp" |
33 #include "memory/metaspace/metachunk.hpp" |
32 #include "memory/metaspace/metaDebug.hpp" |
34 #include "memory/metaspace/metaDebug.hpp" |
33 #include "memory/metaspace/metaspaceCommon.hpp" |
35 #include "memory/metaspace/metaspaceCommon.hpp" |
34 #include "memory/metaspace/metaspaceStatistics.hpp" |
36 #include "memory/metaspace/metaspaceStatistics.hpp" |
35 #include "memory/metaspace/smallBlocks.hpp" |
37 #include "memory/metaspace/smallBlocks.hpp" |
155 _block_freelist = new BlockFreelist(); // Create only on demand |
157 _block_freelist = new BlockFreelist(); // Create only on demand |
156 } |
158 } |
157 _block_freelist->return_block(p, word_size); |
159 _block_freelist->return_block(p, word_size); |
158 } |
160 } |
159 |
161 |
|
162 |
|
163 void SpaceManager::create_lom() { |
|
164 assert(_lom == NULL, "Only call once"); |
|
165 _lom = new LeftOverManager(); |
|
166 } |
|
167 |
|
168 void SpaceManager::add_allocation_to_lom(MetaWord* p, size_t word_size) { |
|
169 if (_lom == NULL) { |
|
170 _lom = new LeftOverManager(); // Create only on demand |
|
171 } |
|
172 _lom->add_block(p, word_size); |
|
173 } |
|
174 |
160 SpaceManager::SpaceManager(ChunkManager* chunk_manager, |
175 SpaceManager::SpaceManager(ChunkManager* chunk_manager, |
161 const ChunkAllocSequence* alloc_sequence, |
176 const ChunkAllocSequence* alloc_sequence, |
162 Mutex* lock, |
177 Mutex* lock, |
163 SizeAtomicCounter* total_used_words_counter, |
178 SizeAtomicCounter* total_used_words_counter, |
164 const char* name, |
179 const char* name, |
165 bool is_micro_loader) |
180 bool is_micro_loader) |
166 : _lock(lock), |
181 : _lock(lock), |
167 _chunk_manager(chunk_manager), |
182 _chunk_manager(chunk_manager), |
168 _chunk_alloc_sequence(alloc_sequence), |
183 _chunk_alloc_sequence(alloc_sequence), |
169 _chunks(), |
184 _chunks(), |
170 _block_freelist(NULL), |
185 _block_freelist(NULL), _lom(NULL), |
171 _total_used_words_counter(total_used_words_counter), |
186 _total_used_words_counter(total_used_words_counter), |
172 _name(name), |
187 _name(name), |
173 _is_micro_loader(is_micro_loader) |
188 _is_micro_loader(is_micro_loader) |
174 { |
189 { |
175 } |
190 } |
189 } |
204 } |
190 |
205 |
191 DEBUG_ONLY(chunk_manager()->verify(true);) |
206 DEBUG_ONLY(chunk_manager()->verify(true);) |
192 |
207 |
193 delete _block_freelist; |
208 delete _block_freelist; |
|
209 delete _lom; |
194 |
210 |
195 } |
211 } |
196 |
212 |
197 // The remaining committed free space in the current chunk is chopped up and stored in the block |
213 // The remaining committed free space in the current chunk is chopped up and stored in the block |
198 // free list for later use. As a result, the current chunk will remain current but completely |
214 // free list for later use. As a result, the current chunk will remain current but completely |
228 LOGFMT_SPCMGR_ARGS, p2i(this), METACHUNK_FULL_FORMAT_ARGS(c)); |
244 LOGFMT_SPCMGR_ARGS, p2i(this), METACHUNK_FULL_FORMAT_ARGS(c)); |
229 |
245 |
230 bool did_hit_limit = false; |
246 bool did_hit_limit = false; |
231 MetaWord* ptr = c->allocate(net_remaining_words, &did_hit_limit); |
247 MetaWord* ptr = c->allocate(net_remaining_words, &did_hit_limit); |
232 assert(ptr != NULL && did_hit_limit == false, "Should have worked"); |
248 assert(ptr != NULL && did_hit_limit == false, "Should have worked"); |
233 add_allocation_to_block_freelist(ptr, net_remaining_words); |
249 |
|
250 if (Settings::use_lom()) { |
|
251 add_allocation_to_lom(ptr, net_remaining_words); |
|
252 } else { |
|
253 add_allocation_to_block_freelist(ptr, net_remaining_words); |
|
254 } |
|
255 |
234 _total_used_words_counter->increment_by(net_remaining_words); |
256 _total_used_words_counter->increment_by(net_remaining_words); |
235 |
257 |
236 // After this operation: the current chunk should have (almost) no free committed space left. |
258 // After this operation: the current chunk should have (almost) no free committed space left. |
237 assert(current_chunk()->free_below_committed_words() <= highest_possible_delta_between_raw_and_net_size, |
259 assert(current_chunk()->free_below_committed_words() <= highest_possible_delta_between_raw_and_net_size, |
238 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
260 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
279 // Allocation from the dictionary is expensive in the sense that |
301 // Allocation from the dictionary is expensive in the sense that |
280 // the dictionary has to be searched for a size. Don't allocate |
302 // the dictionary has to be searched for a size. Don't allocate |
281 // from the dictionary until it starts to get fat. Is this |
303 // from the dictionary until it starts to get fat. Is this |
282 // a reasonable policy? Maybe an skinny dictionary is fast enough |
304 // a reasonable policy? Maybe an skinny dictionary is fast enough |
283 // for allocations. Do some profiling. JJJ |
305 // for allocations. Do some profiling. JJJ |
|
306 if (Settings::use_lom()) { |
|
307 if (_lom != NULL) { |
|
308 p = _lom->get_block(raw_word_size); |
|
309 if (p != NULL) { |
|
310 DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();) |
|
311 log_trace(metaspace)(LOGFMT_SPCMGR ": .. taken from freelist.", LOGFMT_SPCMGR_ARGS); |
|
312 // Note: space in the freeblock dictionary counts as used (see retire_current_chunk()) - |
|
313 // that means that we must not increase the used counter again when allocating from the dictionary. |
|
314 // Therefore we return here. |
|
315 return p; |
|
316 } |
|
317 } |
|
318 } else { |
284 if (_block_freelist != NULL && _block_freelist->total_size() > Settings::allocation_from_dictionary_limit()) { |
319 if (_block_freelist != NULL && _block_freelist->total_size() > Settings::allocation_from_dictionary_limit()) { |
285 p = _block_freelist->get_block(raw_word_size); |
320 p = _block_freelist->get_block(raw_word_size); |
286 |
321 |
287 if (p != NULL) { |
322 if (p != NULL) { |
288 DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();) |
323 DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();) |
291 // that means that we must not increase the used counter again when allocating from the dictionary. |
326 // that means that we must not increase the used counter again when allocating from the dictionary. |
292 // Therefore we return here. |
327 // Therefore we return here. |
293 return p; |
328 return p; |
294 } |
329 } |
295 |
330 |
|
331 } |
296 } |
332 } |
297 |
333 |
298 // 2) Failing that, attempt to allocate from the current chunk. If we hit commit limit, return NULL. |
334 // 2) Failing that, attempt to allocate from the current chunk. If we hit commit limit, return NULL. |
299 if (p == NULL && !did_hit_limit) { |
335 if (p == NULL && !did_hit_limit) { |
300 p = current_chunk()->allocate(raw_word_size, &did_hit_limit); |
336 p = current_chunk()->allocate(raw_word_size, &did_hit_limit); |
403 if (current_chunk()->attempt_rollback_allocation(p, raw_word_size)) { |
439 if (current_chunk()->attempt_rollback_allocation(p, raw_word_size)) { |
404 log_trace(metaspace)(LOGFMT_SPCMGR ": ... rollback succeeded.", LOGFMT_SPCMGR_ARGS); |
440 log_trace(metaspace)(LOGFMT_SPCMGR ": ... rollback succeeded.", LOGFMT_SPCMGR_ARGS); |
405 return; |
441 return; |
406 } |
442 } |
407 |
443 |
408 add_allocation_to_block_freelist(p, raw_word_size); |
444 if (Settings::use_lom()) { |
|
445 add_allocation_to_lom(p, raw_word_size); |
|
446 } else { |
|
447 add_allocation_to_block_freelist(p, raw_word_size); |
|
448 } |
409 |
449 |
410 DEBUG_ONLY(verify_locked();) |
450 DEBUG_ONLY(verify_locked();) |
411 |
451 |
412 } |
452 } |
413 |
453 |
435 } else { |
475 } else { |
436 ucs.waste_words += c->free_below_committed_words(); |
476 ucs.waste_words += c->free_below_committed_words(); |
437 } |
477 } |
438 } |
478 } |
439 |
479 |
440 if (block_freelist() != NULL) { |
480 if (Settings::use_lom()) { |
441 out->free_blocks_num += block_freelist()->num_blocks(); |
481 if (lom() != NULL) { |
442 out->free_blocks_word_size += block_freelist()->total_size(); |
482 block_stats_t s; |
|
483 lom()->statistics(&s); |
|
484 out->free_blocks_num += s.num_blocks; |
|
485 out->free_blocks_word_size += s.word_size; |
|
486 } |
|
487 } else { |
|
488 if (block_freelist() != NULL) { |
|
489 out->free_blocks_num += block_freelist()->num_blocks(); |
|
490 out->free_blocks_word_size += block_freelist()->total_size(); |
|
491 } |
443 } |
492 } |
444 |
493 |
445 SOMETIMES(out->verify();) |
494 SOMETIMES(out->verify();) |
446 |
495 |
447 } |
496 } |