Mercurial > hg > graal-jvmci-8
annotate src/share/vm/memory/threadLocalAllocBuffer.cpp @ 12233:40136aa2cdb1
8010722: assert: failed: heap size is too big for compressed oops
Summary: Use conservative assumptions of required alignment for the various garbage collector components into account when determining the maximum heap size that supports compressed oops. Using this conservative value avoids several circular dependencies in the calculation.
Reviewed-by: stefank, dholmes
author | tschatzl |
---|---|
date | Wed, 11 Sep 2013 16:25:02 +0200 |
parents | f34d701e952e |
children | 579ee1eb0f30 1e1c8d358b52 |
rev | line source |
---|---|
0 | 1 /* |
2100
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1165
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1165
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1165
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "memory/genCollectedHeap.hpp" | |
27 #include "memory/resourceArea.hpp" | |
28 #include "memory/threadLocalAllocBuffer.inline.hpp" | |
29 #include "memory/universe.inline.hpp" | |
30 #include "oops/oop.inline.hpp" | |
7180
f34d701e952e
8003935: Simplify the needed includes for using Thread::current()
stefank
parents:
3960
diff
changeset
|
31 #include "runtime/thread.inline.hpp" |
1972 | 32 #include "utilities/copy.hpp" |
0 | 33 |
1972 | 34 // Thread-Local Edens support |
0 | 35 |
36 // static member initialization | |
37 unsigned ThreadLocalAllocBuffer::_target_refills = 0; | |
38 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL; | |
39 | |
40 void ThreadLocalAllocBuffer::clear_before_allocation() { | |
41 _slow_refill_waste += (unsigned)remaining(); | |
42 make_parsable(true); // also retire the TLAB | |
43 } | |
44 | |
45 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() { | |
46 global_stats()->initialize(); | |
47 | |
48 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { | |
49 thread->tlab().accumulate_statistics(); | |
50 thread->tlab().initialize_statistics(); | |
51 } | |
52 | |
53 // Publish new stats if some allocation occurred. | |
54 if (global_stats()->allocation() != 0) { | |
55 global_stats()->publish(); | |
56 if (PrintTLAB) { | |
57 global_stats()->print(); | |
58 } | |
59 } | |
60 } | |
61 | |
62 void ThreadLocalAllocBuffer::accumulate_statistics() { | |
63 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize; | |
64 size_t unused = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; | |
65 size_t used = capacity - unused; | |
66 | |
67 // Update allocation history if a reasonable amount of eden was allocated. | |
68 bool update_allocation_history = used > 0.5 * capacity; | |
69 | |
70 _gc_waste += (unsigned)remaining(); | |
71 | |
72 if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { | |
73 print_stats("gc"); | |
74 } | |
75 | |
76 if (_number_of_refills > 0) { | |
77 | |
78 if (update_allocation_history) { | |
79 // Average the fraction of eden allocated in a tlab by this | |
80 // thread for use in the next resize operation. | |
81 // _gc_waste is not subtracted because it's included in | |
82 // "used". | |
83 size_t allocation = _number_of_refills * desired_size(); | |
84 double alloc_frac = allocation / (double) used; | |
85 _allocation_fraction.sample(alloc_frac); | |
86 } | |
87 global_stats()->update_allocating_threads(); | |
88 global_stats()->update_number_of_refills(_number_of_refills); | |
89 global_stats()->update_allocation(_number_of_refills * desired_size()); | |
90 global_stats()->update_gc_waste(_gc_waste); | |
91 global_stats()->update_slow_refill_waste(_slow_refill_waste); | |
92 global_stats()->update_fast_refill_waste(_fast_refill_waste); | |
93 | |
94 } else { | |
95 assert(_number_of_refills == 0 && _fast_refill_waste == 0 && | |
96 _slow_refill_waste == 0 && _gc_waste == 0, | |
97 "tlab stats == 0"); | |
98 } | |
99 global_stats()->update_slow_allocations(_slow_allocations); | |
100 } | |
101 | |
102 // Fills the current tlab with a dummy filler array to create | |
103 // an illusion of a contiguous Eden and optionally retires the tlab. | |
104 // Waste accounting should be done in caller as appropriate; see, | |
105 // for example, clear_before_allocation(). | |
106 void ThreadLocalAllocBuffer::make_parsable(bool retire) { | |
107 if (end() != NULL) { | |
108 invariants(); | |
2100
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
109 |
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
110 if (retire) { |
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
111 myThread()->incr_allocated_bytes(used_bytes()); |
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
112 } |
b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
phh
parents:
1972
diff
changeset
|
113 |
1165
2dd52dea6d28
6902115: G1:assert(ignore_max_completed||thread->is_Java_thread()||SafepointSynchronize::is_at_safepoint())
johnc
parents:
579
diff
changeset
|
114 CollectedHeap::fill_with_object(top(), hard_end(), retire); |
0 | 115 |
116 if (retire || ZeroTLAB) { // "Reset" the TLAB | |
117 set_start(NULL); | |
118 set_top(NULL); | |
119 set_pf_top(NULL); | |
120 set_end(NULL); | |
121 } | |
122 } | |
123 assert(!(retire || ZeroTLAB) || | |
124 (start() == NULL && end() == NULL && top() == NULL), | |
125 "TLAB must be reset"); | |
126 } | |
127 | |
128 void ThreadLocalAllocBuffer::resize_all_tlabs() { | |
129 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { | |
130 thread->tlab().resize(); | |
131 } | |
132 } | |
133 | |
134 void ThreadLocalAllocBuffer::resize() { | |
135 | |
136 if (ResizeTLAB) { | |
137 // Compute the next tlab size using expected allocation amount | |
138 size_t alloc = (size_t)(_allocation_fraction.average() * | |
139 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize)); | |
140 size_t new_size = alloc / _target_refills; | |
141 | |
142 new_size = MIN2(MAX2(new_size, min_size()), max_size()); | |
143 | |
144 size_t aligned_new_size = align_object_size(new_size); | |
145 | |
146 if (PrintTLAB && Verbose) { | |
147 gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" | |
148 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", | |
149 myThread(), myThread()->osthread()->thread_id(), | |
150 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); | |
151 } | |
152 set_desired_size(aligned_new_size); | |
153 | |
154 set_refill_waste_limit(initial_refill_waste_limit()); | |
155 } | |
156 } | |
157 | |
158 void ThreadLocalAllocBuffer::initialize_statistics() { | |
159 _number_of_refills = 0; | |
160 _fast_refill_waste = 0; | |
161 _slow_refill_waste = 0; | |
162 _gc_waste = 0; | |
163 _slow_allocations = 0; | |
164 } | |
165 | |
166 void ThreadLocalAllocBuffer::fill(HeapWord* start, | |
167 HeapWord* top, | |
168 size_t new_size) { | |
169 _number_of_refills++; | |
170 if (PrintTLAB && Verbose) { | |
171 print_stats("fill"); | |
172 } | |
173 assert(top <= start + new_size - alignment_reserve(), "size too small"); | |
174 initialize(start, top, start + new_size - alignment_reserve()); | |
175 | |
176 // Reset amount of internal fragmentation | |
177 set_refill_waste_limit(initial_refill_waste_limit()); | |
178 } | |
179 | |
180 void ThreadLocalAllocBuffer::initialize(HeapWord* start, | |
181 HeapWord* top, | |
182 HeapWord* end) { | |
183 set_start(start); | |
184 set_top(top); | |
185 set_pf_top(top); | |
186 set_end(end); | |
187 invariants(); | |
188 } | |
189 | |
190 void ThreadLocalAllocBuffer::initialize() { | |
191 initialize(NULL, // start | |
192 NULL, // top | |
193 NULL); // end | |
194 | |
195 set_desired_size(initial_desired_size()); | |
196 | |
197 // Following check is needed because at startup the main (primordial) | |
198 // thread is initialized before the heap is. The initialization for | |
199 // this thread is redone in startup_initialization below. | |
200 if (Universe::heap() != NULL) { | |
201 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize; | |
202 double alloc_frac = desired_size() * target_refills() / (double) capacity; | |
203 _allocation_fraction.sample(alloc_frac); | |
204 } | |
205 | |
206 set_refill_waste_limit(initial_refill_waste_limit()); | |
207 | |
208 initialize_statistics(); | |
209 } | |
210 | |
211 void ThreadLocalAllocBuffer::startup_initialization() { | |
212 | |
213 // Assuming each thread's active tlab is, on average, | |
214 // 1/2 full at a GC | |
215 _target_refills = 100 / (2 * TLABWasteTargetPercent); | |
216 _target_refills = MAX2(_target_refills, (unsigned)1U); | |
217 | |
218 _global_stats = new GlobalTLABStats(); | |
219 | |
220 // During jvm startup, the main (primordial) thread is initialized | |
221 // before the heap is initialized. So reinitialize it now. | |
222 guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread"); | |
223 Thread::current()->tlab().initialize(); | |
224 | |
225 if (PrintTLAB && Verbose) { | |
226 gclog_or_tty->print("TLAB min: " SIZE_FORMAT " initial: " SIZE_FORMAT " max: " SIZE_FORMAT "\n", | |
227 min_size(), Thread::current()->tlab().initial_desired_size(), max_size()); | |
228 } | |
229 } | |
230 | |
231 size_t ThreadLocalAllocBuffer::initial_desired_size() { | |
232 size_t init_sz; | |
233 | |
234 if (TLABSize > 0) { | |
235 init_sz = MIN2(TLABSize / HeapWordSize, max_size()); | |
236 } else if (global_stats() == NULL) { | |
237 // Startup issue - main thread initialized before heap initialized. | |
238 init_sz = min_size(); | |
239 } else { | |
240 // Initial size is a function of the average number of allocating threads. | |
241 unsigned nof_threads = global_stats()->allocating_threads_avg(); | |
242 | |
243 init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) / | |
244 (nof_threads * target_refills()); | |
245 init_sz = align_object_size(init_sz); | |
246 init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); | |
247 } | |
248 return init_sz; | |
249 } | |
250 | |
251 const size_t ThreadLocalAllocBuffer::max_size() { | |
252 | |
253 // TLABs can't be bigger than we can fill with a int[Integer.MAX_VALUE]. | |
254 // This restriction could be removed by enabling filling with multiple arrays. | |
255 // If we compute that the reasonable way as | |
256 // header_size + ((sizeof(jint) * max_jint) / HeapWordSize) | |
257 // we'll overflow on the multiply, so we do the divide first. | |
258 // We actually lose a little by dividing first, | |
259 // but that just makes the TLAB somewhat smaller than the biggest array, | |
260 // which is fine, since we'll be able to fill that. | |
261 | |
262 size_t unaligned_max_size = typeArrayOopDesc::header_size(T_INT) + | |
263 sizeof(jint) * | |
264 ((juint) max_jint / (size_t) HeapWordSize); | |
265 return align_size_down(unaligned_max_size, MinObjAlignment); | |
266 } | |
267 | |
268 void ThreadLocalAllocBuffer::print_stats(const char* tag) { | |
269 Thread* thrd = myThread(); | |
270 size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; | |
271 size_t alloc = _number_of_refills * _desired_size; | |
272 double waste_percent = alloc == 0 ? 0.0 : | |
273 100.0 * waste / alloc; | |
274 size_t tlab_used = Universe::heap()->tlab_capacity(thrd) - | |
275 Universe::heap()->unsafe_max_tlab_alloc(thrd); | |
276 gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" | |
277 " desired_size: " SIZE_FORMAT "KB" | |
278 " slow allocs: %d refill waste: " SIZE_FORMAT "B" | |
279 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB" | |
280 " slow: %dB fast: %dB\n", | |
281 tag, thrd, thrd->osthread()->thread_id(), | |
282 _desired_size / (K / HeapWordSize), | |
283 _slow_allocations, _refill_waste_limit * HeapWordSize, | |
284 _allocation_fraction.average(), | |
285 _allocation_fraction.average() * tlab_used / K, | |
286 _number_of_refills, waste_percent, | |
287 _gc_waste * HeapWordSize, | |
288 _slow_refill_waste * HeapWordSize, | |
289 _fast_refill_waste * HeapWordSize); | |
290 } | |
291 | |
292 void ThreadLocalAllocBuffer::verify() { | |
293 HeapWord* p = start(); | |
294 HeapWord* t = top(); | |
295 HeapWord* prev_p = NULL; | |
296 while (p < t) { | |
297 oop(p)->verify(); | |
298 prev_p = p; | |
299 p += oop(p)->size(); | |
300 } | |
301 guarantee(p == top(), "end of last object must match end of space"); | |
302 } | |
303 | |
304 Thread* ThreadLocalAllocBuffer::myThread() { | |
305 return (Thread*)(((char *)this) + | |
306 in_bytes(start_offset()) - | |
307 in_bytes(Thread::tlab_start_offset())); | |
308 } | |
309 | |
310 | |
311 GlobalTLABStats::GlobalTLABStats() : | |
312 _allocating_threads_avg(TLABAllocationWeight) { | |
313 | |
314 initialize(); | |
315 | |
316 _allocating_threads_avg.sample(1); // One allocating thread at startup | |
317 | |
318 if (UsePerfData) { | |
319 | |
320 EXCEPTION_MARK; | |
321 ResourceMark rm; | |
322 | |
323 char* cname = PerfDataManager::counter_name("tlab", "allocThreads"); | |
324 _perf_allocating_threads = | |
325 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK); | |
326 | |
327 cname = PerfDataManager::counter_name("tlab", "fills"); | |
328 _perf_total_refills = | |
329 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK); | |
330 | |
331 cname = PerfDataManager::counter_name("tlab", "maxFills"); | |
332 _perf_max_refills = | |
333 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK); | |
334 | |
335 cname = PerfDataManager::counter_name("tlab", "alloc"); | |
336 _perf_allocation = | |
337 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
338 | |
339 cname = PerfDataManager::counter_name("tlab", "gcWaste"); | |
340 _perf_gc_waste = | |
341 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
342 | |
343 cname = PerfDataManager::counter_name("tlab", "maxGcWaste"); | |
344 _perf_max_gc_waste = | |
345 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
346 | |
347 cname = PerfDataManager::counter_name("tlab", "slowWaste"); | |
348 _perf_slow_refill_waste = | |
349 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
350 | |
351 cname = PerfDataManager::counter_name("tlab", "maxSlowWaste"); | |
352 _perf_max_slow_refill_waste = | |
353 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
354 | |
355 cname = PerfDataManager::counter_name("tlab", "fastWaste"); | |
356 _perf_fast_refill_waste = | |
357 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
358 | |
359 cname = PerfDataManager::counter_name("tlab", "maxFastWaste"); | |
360 _perf_max_fast_refill_waste = | |
361 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); | |
362 | |
363 cname = PerfDataManager::counter_name("tlab", "slowAlloc"); | |
364 _perf_slow_allocations = | |
365 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK); | |
366 | |
367 cname = PerfDataManager::counter_name("tlab", "maxSlowAlloc"); | |
368 _perf_max_slow_allocations = | |
369 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK); | |
370 } | |
371 } | |
372 | |
373 void GlobalTLABStats::initialize() { | |
374 // Clear counters summarizing info from all threads | |
375 _allocating_threads = 0; | |
376 _total_refills = 0; | |
377 _max_refills = 0; | |
378 _total_allocation = 0; | |
379 _total_gc_waste = 0; | |
380 _max_gc_waste = 0; | |
381 _total_slow_refill_waste = 0; | |
382 _max_slow_refill_waste = 0; | |
383 _total_fast_refill_waste = 0; | |
384 _max_fast_refill_waste = 0; | |
385 _total_slow_allocations = 0; | |
386 _max_slow_allocations = 0; | |
387 } | |
388 | |
389 void GlobalTLABStats::publish() { | |
390 _allocating_threads_avg.sample(_allocating_threads); | |
391 if (UsePerfData) { | |
392 _perf_allocating_threads ->set_value(_allocating_threads); | |
393 _perf_total_refills ->set_value(_total_refills); | |
394 _perf_max_refills ->set_value(_max_refills); | |
395 _perf_allocation ->set_value(_total_allocation); | |
396 _perf_gc_waste ->set_value(_total_gc_waste); | |
397 _perf_max_gc_waste ->set_value(_max_gc_waste); | |
398 _perf_slow_refill_waste ->set_value(_total_slow_refill_waste); | |
399 _perf_max_slow_refill_waste->set_value(_max_slow_refill_waste); | |
400 _perf_fast_refill_waste ->set_value(_total_fast_refill_waste); | |
401 _perf_max_fast_refill_waste->set_value(_max_fast_refill_waste); | |
402 _perf_slow_allocations ->set_value(_total_slow_allocations); | |
403 _perf_max_slow_allocations ->set_value(_max_slow_allocations); | |
404 } | |
405 } | |
406 | |
407 void GlobalTLABStats::print() { | |
408 size_t waste = _total_gc_waste + _total_slow_refill_waste + _total_fast_refill_waste; | |
409 double waste_percent = _total_allocation == 0 ? 0.0 : | |
410 100.0 * waste / _total_allocation; | |
411 gclog_or_tty->print("TLAB totals: thrds: %d refills: %d max: %d" | |
412 " slow allocs: %d max %d waste: %4.1f%%" | |
413 " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" | |
414 " slow: " SIZE_FORMAT "B max: " SIZE_FORMAT "B" | |
415 " fast: " SIZE_FORMAT "B max: " SIZE_FORMAT "B\n", | |
416 _allocating_threads, | |
417 _total_refills, _max_refills, | |
418 _total_slow_allocations, _max_slow_allocations, | |
419 waste_percent, | |
420 _total_gc_waste * HeapWordSize, | |
421 _max_gc_waste * HeapWordSize, | |
422 _total_slow_refill_waste * HeapWordSize, | |
423 _max_slow_refill_waste * HeapWordSize, | |
424 _total_fast_refill_waste * HeapWordSize, | |
425 _max_fast_refill_waste * HeapWordSize); | |
426 } |