79 } |
79 } |
80 return byte_size / BytesPerWord; |
80 return byte_size / BytesPerWord; |
81 |
81 |
82 } |
82 } |
83 |
83 |
84 |
|
85 |
|
86 // Given a requested word size, will allocate a chunk large enough to at least fit that |
84 // Given a requested word size, will allocate a chunk large enough to at least fit that |
87 // size, but may be larger according to the rules in the ChunkAllocSequence. |
85 // size, but may be larger according to internal heuristics. |
88 // Updates counters and adds the chunk to the head of the chunk list. |
86 // |
89 Metachunk* SpaceManager::allocate_chunk_to_fit(size_t requested_word_size) { |
87 // On success, it will replace the current chunk with the newly allocated one, which will |
|
88 // become the current chunk. The old current chunk should be retired beforehand. |
|
89 // |
|
90 // May fail if we could not allocate a new chunk. In that case the current chunk remains |
|
91 // unchanged and false is returned. |
|
92 bool SpaceManager::allocate_new_current_chunk(size_t requested_word_size) { |
90 |
93 |
91 assert_lock_strong(lock()); |
94 assert_lock_strong(lock()); |
92 |
95 |
93 guarantee(requested_word_size < chklvl::MAX_CHUNK_WORD_SIZE, |
96 guarantee(requested_word_size < chklvl::MAX_CHUNK_WORD_SIZE, |
94 "Requested size too large (" SIZE_FORMAT ").", requested_word_size); |
97 "Requested size too large (" SIZE_FORMAT ").", requested_word_size); |
95 |
98 |
|
99 // If we have a current chunk, it should have been retired (almost empty) beforehand. |
|
100 // See: retire_current_chunk(). |
|
101 assert(current_chunk() == NULL || current_chunk()->free_below_committed_words() <= 10, "Must retire chunk beforehand"); |
|
102 |
96 const chklvl_t min_level = chklvl::level_fitting_word_size(requested_word_size); |
103 const chklvl_t min_level = chklvl::level_fitting_word_size(requested_word_size); |
97 chklvl_t pref_level = _chunk_alloc_sequence->get_next_chunk_level(_chunks.size()); |
104 chklvl_t pref_level = _chunk_alloc_sequence->get_next_chunk_level(_chunks.size()); |
98 |
105 |
99 if (pref_level > min_level) { |
106 if (pref_level > min_level) { |
100 pref_level = min_level; |
107 pref_level = min_level; |
101 } |
108 } |
102 |
109 |
103 Metachunk* c = _chunk_manager->get_chunk(min_level, pref_level); |
110 Metachunk* c = _chunk_manager->get_chunk(min_level, pref_level); |
104 assert(c != NULL, "Could not get a chunk"); |
111 if (c == NULL) { |
|
112 log_debug(metaspace)("SpaceManager %s: failed to allocate new chunk for requested word size " SIZE_FORMAT ".", |
|
113 _name, requested_word_size); |
|
114 return false; |
|
115 } |
|
116 |
105 assert(c->is_in_use(), "Wrong chunk state."); |
117 assert(c->is_in_use(), "Wrong chunk state."); |
106 assert(c->level() <= min_level && c->level() >= pref_level, "Sanity"); |
118 assert(c->level() <= min_level && c->level() >= pref_level, "Sanity"); |
107 |
119 |
108 _chunks.add(c); |
120 _chunks.add(c); |
109 |
121 |
162 |
171 |
163 delete _block_freelist; |
172 delete _block_freelist; |
164 |
173 |
165 } |
174 } |
166 |
175 |
167 // The current chunk is unable to service a request. The remainder of the chunk is |
176 // The remaining committed free space in the current chunk is chopped up and stored in the block |
168 // chopped into blocks and fed into the _block_freelists, in the hope of later reuse. |
177 // free list for later use. As a result, the current chunk will remain current but completely |
|
178 // used up. This is a preparation for calling allocate_new_current_chunk(). |
169 void SpaceManager::retire_current_chunk() { |
179 void SpaceManager::retire_current_chunk() { |
170 assert_lock_strong(lock()); |
180 assert_lock_strong(lock()); |
171 |
181 |
172 Metachunk* c = current_chunk(); |
182 Metachunk* c = current_chunk(); |
173 assert(c != NULL, "Sanity"); |
183 assert(c != NULL, "Sanity"); |
174 |
184 |
175 log_debug(metaspace)("SpaceManager %s: retiring chunk " METACHUNK_FULL_FORMAT ".", |
185 log_debug(metaspace)("SpaceManager %s: retiring chunk " METACHUNK_FULL_FORMAT ".", |
176 _name, METACHUNK_FULL_FORMAT_ARGS(c)); |
186 _name, METACHUNK_FULL_FORMAT_ARGS(c)); |
177 |
187 |
178 // We can run into very rare situations where we would retire a completely empty chunk. |
188 // Side note: |
179 // This should be exceedingly rare: the chunk was created to fit a prior, smaller, allocation, |
189 // In theory it could happen that we are asked to retire a completely empty chunk. This may be the |
180 // and then the allocation did not go thru since we hit the commit limit, or was immediately |
190 // result of rolled back allocations (see deallocate in place) and a lot of luck. |
181 // immediately deallocated and that hit the fast path (see Metachunk::attempt_roll_back_allocation()). |
191 // But since these cases should be exceedingly rare, we do not handle them special in order to keep |
182 // Then, that allocation was followed by a larger allocation which is too small for the still |
192 // the code simple. |
183 // empty current chunk. |
193 |
184 if (c->used_words() == 0) { |
194 size_t raw_remaining_words = c->free_below_committed_words(); |
185 // (A) |
195 size_t net_remaining_words = get_net_allocation_word_size(raw_remaining_words); |
186 log_trace(metaspace)("SpaceManager %s: ... completely empty, return to freelist: chunk" METACHUNK_FORMAT ".", |
196 if (net_remaining_words > 0) { |
187 _name, METACHUNK_FORMAT_ARGS(c)); |
197 bool did_hit_limit = false; |
188 |
198 MetaWord* ptr = c->allocate(net_remaining_words, &did_hit_limit); |
189 // Remove the current chunk from our list and return it to the chunk manager. |
199 assert(ptr != NULL && did_hit_limit == false, "Should have worked"); |
190 _chunks.remove(c); |
200 add_allocation_to_block_freelist(ptr, net_remaining_words); |
191 _chunk_manager->return_chunk(c); |
201 _total_used_words_counter->increment_by(net_remaining_words); |
192 |
|
193 } else { |
|
194 // (B) |
|
195 size_t raw_remaining_words = c->free_below_committed_words(); |
|
196 size_t net_remaining_words = get_net_allocation_word_size(raw_remaining_words); |
|
197 if (net_remaining_words > 0) { |
|
198 bool did_hit_limit = false; |
|
199 MetaWord* ptr = c->allocate(net_remaining_words, &did_hit_limit); |
|
200 assert(ptr != NULL && did_hit_limit == false, "Should have worked"); |
|
201 add_allocation_to_block_freelist(ptr, net_remaining_words); |
|
202 _total_used_words_counter->increment_by(net_remaining_words); |
|
203 } |
|
204 } |
202 } |
205 |
203 |
206 // After this operation: the current chunk should have (almost) no free committed space left. |
204 // After this operation: the current chunk should have (almost) no free committed space left. |
207 // It could also be NULL, if we hit case (A) and returned the only chunk in this space manager. |
205 assert(current_chunk()->free_below_committed_words() <= highest_possible_delta_between_raw_and_net_size, |
208 assert(current_chunk() == NULL || |
|
209 current_chunk()->free_below_committed_words() <= highest_possible_delta_between_raw_and_net_size, |
|
210 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
206 "Chunk retiring did not work (current chunk " METACHUNK_FULL_FORMAT ").", |
211 METACHUNK_FULL_FORMAT_ARGS(current_chunk())); |
207 METACHUNK_FULL_FORMAT_ARGS(current_chunk())); |
212 |
208 |
213 } |
209 } |
214 |
210 |
232 |
228 |
233 bool did_hit_limit = false; |
229 bool did_hit_limit = false; |
234 |
230 |
235 // Allocate first chunk if needed. |
231 // Allocate first chunk if needed. |
236 if (current_chunk() == NULL) { |
232 if (current_chunk() == NULL) { |
237 Metachunk* c = allocate_chunk_to_fit(raw_word_size); |
233 if (allocate_new_current_chunk(raw_word_size) == false) { |
238 assert(c != NULL && _chunks.size() == 1 && c == current_chunk(), "Should be"); |
234 did_hit_limit = true; |
|
235 } else { |
|
236 assert(current_chunk() != NULL && current_chunk()->free_words() >= raw_word_size, "Sanity"); |
|
237 } |
239 } |
238 } |
240 |
239 |
241 // 1) Attempt to allocate from the dictionary of deallocated blocks. |
240 // 1) Attempt to allocate from the dictionary of deallocated blocks. |
242 |
241 |
243 // Allocation from the dictionary is expensive in the sense that |
242 // Allocation from the dictionary is expensive in the sense that |
307 retire_current_chunk(); |
306 retire_current_chunk(); |
308 |
307 |
309 DEBUG_ONLY(InternalStats::inc_num_chunks_retired();) |
308 DEBUG_ONLY(InternalStats::inc_num_chunks_retired();) |
310 |
309 |
311 // Allocate a new chunk. |
310 // Allocate a new chunk. |
312 Metachunk* c = allocate_chunk_to_fit(raw_word_size); |
311 if (allocate_new_current_chunk(raw_word_size) == false) { |
313 assert(c != NULL && _chunks.size() > 0 && c == current_chunk(), "Should be"); |
312 did_hit_limit = true; |
314 |
313 } else { |
315 p = current_chunk()->allocate(raw_word_size, &did_hit_limit); |
314 assert(current_chunk() != NULL && current_chunk()->free_words() >= raw_word_size, "Sanity"); |
316 log_trace(metaspace)("SpaceManager %s: .. allocated new chunk " CHKLVL_FORMAT " and taken from that.", |
315 p = current_chunk()->allocate(raw_word_size, &did_hit_limit); |
317 _name, current_chunk()->level()); |
316 log_trace(metaspace)("SpaceManager %s: .. allocated new chunk " CHKLVL_FORMAT " and taken from that.", |
|
317 _name, current_chunk()->level()); |
|
318 } |
318 |
319 |
319 } |
320 } |
320 |
321 |
321 assert(p != NULL || (p == NULL && did_hit_limit), "Sanity"); |
322 assert(p != NULL || (p == NULL && did_hit_limit), "Sanity"); |
322 |
323 |
323 if (p == NULL) { |
324 if (p == NULL) { |
324 DEBUG_ONLY(InternalStats::inc_num_allocs_failed_limit();) |
325 DEBUG_ONLY(InternalStats::inc_num_allocs_failed_limit();) |
325 } else { |
326 } else { |
326 DEBUG_ONLY(InternalStats::inc_num_allocs();) |
327 DEBUG_ONLY(InternalStats::inc_num_allocs();) |
|
328 _total_used_words_counter->increment_by(raw_word_size); |
327 } |
329 } |
328 |
330 |
329 log_trace(metaspace)("SpaceManager %s: returned " PTR_FORMAT ".", |
331 log_trace(metaspace)("SpaceManager %s: returned " PTR_FORMAT ".", |
330 _name, p2i(p)); |
332 _name, p2i(p)); |
331 |
|
332 _total_used_words_counter->increment_by(raw_word_size); |
|
333 |
333 |
334 return p; |
334 return p; |
335 |
335 |
336 } |
336 } |
337 |
337 |