Mercurial > hg > graal-jvmci-8
annotate src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @ 1145:e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
Summary: Autonomic per-worker free block cache sizing, tunable coalition policies, fixes to per-size block statistics, retuned gain and bandwidth of some feedback loop filters to allow quicker reactivity to abrupt changes in ambient demand, and other heuristics to reduce fragmentation of the CMS old gen. Also tightened some assertions, including those related to locking.
Reviewed-by: jmasa
author | ysr |
---|---|
date | Wed, 23 Dec 2009 09:23:54 -0800 |
parents | 148e5441d916 |
children | 0bfd3fb24150 |
rev | line source |
---|---|
0 | 1 /* |
579 | 2 * Copyright 2001-2009 Sun Microsystems, Inc. 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 * | |
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_parNewGeneration.cpp.incl" | |
27 | |
28 #ifdef _MSC_VER | |
29 #pragma warning( push ) | |
30 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list | |
31 #endif | |
32 ParScanThreadState::ParScanThreadState(Space* to_space_, | |
33 ParNewGeneration* gen_, | |
34 Generation* old_gen_, | |
35 int thread_num_, | |
36 ObjToScanQueueSet* work_queue_set_, | |
695 | 37 GrowableArray<oop>** overflow_stack_set_, |
0 | 38 size_t desired_plab_sz_, |
39 ParallelTaskTerminator& term_) : | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
40 _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_), |
0 | 41 _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false), |
695 | 42 _overflow_stack(overflow_stack_set_[thread_num_]), |
0 | 43 _ageTable(false), // false ==> not the global age table, no perf data. |
44 _to_space_alloc_buffer(desired_plab_sz_), | |
45 _to_space_closure(gen_, this), _old_gen_closure(gen_, this), | |
46 _to_space_root_closure(gen_, this), _old_gen_root_closure(gen_, this), | |
47 _older_gen_closure(gen_, this), | |
48 _evacuate_followers(this, &_to_space_closure, &_old_gen_closure, | |
49 &_to_space_root_closure, gen_, &_old_gen_root_closure, | |
50 work_queue_set_, &term_), | |
51 _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this), | |
52 _keep_alive_closure(&_scan_weak_ref_closure), | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
53 _promotion_failure_size(0), |
0 | 54 _pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0), |
55 _strong_roots_time(0.0), _term_time(0.0) | |
56 { | |
57 _survivor_chunk_array = | |
58 (ChunkArray*) old_gen()->get_data_recorder(thread_num()); | |
59 _hash_seed = 17; // Might want to take time-based random value. | |
60 _start = os::elapsedTime(); | |
61 _old_gen_closure.set_generation(old_gen_); | |
62 _old_gen_root_closure.set_generation(old_gen_); | |
63 } | |
64 #ifdef _MSC_VER | |
65 #pragma warning( pop ) | |
66 #endif | |
67 | |
68 void ParScanThreadState::record_survivor_plab(HeapWord* plab_start, | |
69 size_t plab_word_size) { | |
70 ChunkArray* sca = survivor_chunk_array(); | |
71 if (sca != NULL) { | |
72 // A non-null SCA implies that we want the PLAB data recorded. | |
73 sca->record_sample(plab_start, plab_word_size); | |
74 } | |
75 } | |
76 | |
77 bool ParScanThreadState::should_be_partially_scanned(oop new_obj, oop old_obj) const { | |
78 return new_obj->is_objArray() && | |
79 arrayOop(new_obj)->length() > ParGCArrayScanChunk && | |
80 new_obj != old_obj; | |
81 } | |
82 | |
83 void ParScanThreadState::scan_partial_array_and_push_remainder(oop old) { | |
84 assert(old->is_objArray(), "must be obj array"); | |
85 assert(old->is_forwarded(), "must be forwarded"); | |
86 assert(Universe::heap()->is_in_reserved(old), "must be in heap."); | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
87 assert(!old_gen()->is_in(old), "must be in young generation."); |
0 | 88 |
89 objArrayOop obj = objArrayOop(old->forwardee()); | |
90 // Process ParGCArrayScanChunk elements now | |
91 // and push the remainder back onto queue | |
92 int start = arrayOop(old)->length(); | |
93 int end = obj->length(); | |
94 int remainder = end - start; | |
95 assert(start <= end, "just checking"); | |
96 if (remainder > 2 * ParGCArrayScanChunk) { | |
97 // Test above combines last partial chunk with a full chunk | |
98 end = start + ParGCArrayScanChunk; | |
99 arrayOop(old)->set_length(end); | |
100 // Push remainder. | |
101 bool ok = work_queue()->push(old); | |
102 assert(ok, "just popped, push must be okay"); | |
103 note_push(); | |
104 } else { | |
105 // Restore length so that it can be used if there | |
106 // is a promotion failure and forwarding pointers | |
107 // must be removed. | |
108 arrayOop(old)->set_length(end); | |
109 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
110 |
0 | 111 // process our set of indices (include header in first chunk) |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
112 // should make sure end is even (aligned to HeapWord in case of compressed oops) |
0 | 113 if ((HeapWord *)obj < young_old_boundary()) { |
114 // object is in to_space | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
115 obj->oop_iterate_range(&_to_space_closure, start, end); |
0 | 116 } else { |
117 // object is in old generation | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
118 obj->oop_iterate_range(&_old_gen_closure, start, end); |
0 | 119 } |
120 } | |
121 | |
122 | |
123 void ParScanThreadState::trim_queues(int max_size) { | |
124 ObjToScanQueue* queue = work_queue(); | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
125 do { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
126 while (queue->size() > (juint)max_size) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
127 oop obj_to_scan; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
128 if (queue->pop_local(obj_to_scan)) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
129 note_pop(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
130 if ((HeapWord *)obj_to_scan < young_old_boundary()) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
131 if (obj_to_scan->is_objArray() && |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
132 obj_to_scan->is_forwarded() && |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
133 obj_to_scan->forwardee() != obj_to_scan) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
134 scan_partial_array_and_push_remainder(obj_to_scan); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
135 } else { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
136 // object is in to_space |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
137 obj_to_scan->oop_iterate(&_to_space_closure); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
138 } |
0 | 139 } else { |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
140 // object is in old generation |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
141 obj_to_scan->oop_iterate(&_old_gen_closure); |
0 | 142 } |
143 } | |
144 } | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
145 // For the case of compressed oops, we have a private, non-shared |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
146 // overflow stack, so we eagerly drain it so as to more evenly |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
147 // distribute load early. Note: this may be good to do in |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
148 // general rather than delay for the final stealing phase. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
149 // If applicable, we'll transfer a set of objects over to our |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
150 // work queue, allowing them to be stolen and draining our |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
151 // private overflow stack. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
152 } while (ParGCTrimOverflow && young_gen()->take_from_overflow_list(this)); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
153 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
154 |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
155 bool ParScanThreadState::take_from_overflow_stack() { |
695 | 156 assert(ParGCUseLocalOverflow, "Else should not call"); |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
157 assert(young_gen()->overflow_list() == NULL, "Error"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
158 ObjToScanQueue* queue = work_queue(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
159 GrowableArray<oop>* of_stack = overflow_stack(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
160 uint num_overflow_elems = of_stack->length(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
161 uint num_take_elems = MIN2(MIN2((queue->max_elems() - queue->size())/4, |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
162 (juint)ParGCDesiredObjsFromOverflowList), |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
163 num_overflow_elems); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
164 // Transfer the most recent num_take_elems from the overflow |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
165 // stack to our work queue. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
166 for (size_t i = 0; i != num_take_elems; i++) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
167 oop cur = of_stack->pop(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
168 oop obj_to_push = cur->forwardee(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
169 assert(Universe::heap()->is_in_reserved(cur), "Should be in heap"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
170 assert(!old_gen()->is_in_reserved(cur), "Should be in young gen"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
171 assert(Universe::heap()->is_in_reserved(obj_to_push), "Should be in heap"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
172 if (should_be_partially_scanned(obj_to_push, cur)) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
173 assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
174 obj_to_push = cur; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
175 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
176 bool ok = queue->push(obj_to_push); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
177 assert(ok, "Should have succeeded"); |
0 | 178 } |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
179 assert(young_gen()->overflow_list() == NULL, "Error"); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
180 return num_take_elems > 0; // was something transferred? |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
181 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
182 |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
183 void ParScanThreadState::push_on_overflow_stack(oop p) { |
695 | 184 assert(ParGCUseLocalOverflow, "Else should not call"); |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
185 overflow_stack()->push(p); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
186 assert(young_gen()->overflow_list() == NULL, "Error"); |
0 | 187 } |
188 | |
189 HeapWord* ParScanThreadState::alloc_in_to_space_slow(size_t word_sz) { | |
190 | |
191 // Otherwise, if the object is small enough, try to reallocate the | |
192 // buffer. | |
193 HeapWord* obj = NULL; | |
194 if (!_to_space_full) { | |
195 ParGCAllocBuffer* const plab = to_space_alloc_buffer(); | |
196 Space* const sp = to_space(); | |
197 if (word_sz * 100 < | |
198 ParallelGCBufferWastePct * plab->word_sz()) { | |
199 // Is small enough; abandon this buffer and start a new one. | |
200 plab->retire(false, false); | |
201 size_t buf_size = plab->word_sz(); | |
202 HeapWord* buf_space = sp->par_allocate(buf_size); | |
203 if (buf_space == NULL) { | |
204 const size_t min_bytes = | |
205 ParGCAllocBuffer::min_size() << LogHeapWordSize; | |
206 size_t free_bytes = sp->free(); | |
207 while(buf_space == NULL && free_bytes >= min_bytes) { | |
208 buf_size = free_bytes >> LogHeapWordSize; | |
209 assert(buf_size == (size_t)align_object_size(buf_size), | |
210 "Invariant"); | |
211 buf_space = sp->par_allocate(buf_size); | |
212 free_bytes = sp->free(); | |
213 } | |
214 } | |
215 if (buf_space != NULL) { | |
216 plab->set_word_size(buf_size); | |
217 plab->set_buf(buf_space); | |
218 record_survivor_plab(buf_space, buf_size); | |
219 obj = plab->allocate(word_sz); | |
220 // Note that we cannot compare buf_size < word_sz below | |
221 // because of AlignmentReserve (see ParGCAllocBuffer::allocate()). | |
222 assert(obj != NULL || plab->words_remaining() < word_sz, | |
223 "Else should have been able to allocate"); | |
224 // It's conceivable that we may be able to use the | |
225 // buffer we just grabbed for subsequent small requests | |
226 // even if not for this one. | |
227 } else { | |
228 // We're used up. | |
229 _to_space_full = true; | |
230 } | |
231 | |
232 } else { | |
233 // Too large; allocate the object individually. | |
234 obj = sp->par_allocate(word_sz); | |
235 } | |
236 } | |
237 return obj; | |
238 } | |
239 | |
240 | |
241 void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj, | |
242 size_t word_sz) { | |
243 // Is the alloc in the current alloc buffer? | |
244 if (to_space_alloc_buffer()->contains(obj)) { | |
245 assert(to_space_alloc_buffer()->contains(obj + word_sz - 1), | |
246 "Should contain whole object."); | |
247 to_space_alloc_buffer()->undo_allocation(obj, word_sz); | |
248 } else { | |
481
7d7a7c599c17
6578152: fill_region_with_object has usability and safety issues
jcoomes
parents:
457
diff
changeset
|
249 CollectedHeap::fill_with_object(obj, word_sz); |
0 | 250 } |
251 } | |
252 | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
253 void ParScanThreadState::print_and_clear_promotion_failure_size() { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
254 if (_promotion_failure_size != 0) { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
255 if (PrintPromotionFailure) { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
256 gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ", |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
257 _thread_num, _promotion_failure_size); |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
258 } |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
259 _promotion_failure_size = 0; |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
260 } |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
261 } |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
262 |
0 | 263 class ParScanThreadStateSet: private ResourceArray { |
264 public: | |
265 // Initializes states for the specified number of threads; | |
266 ParScanThreadStateSet(int num_threads, | |
267 Space& to_space, | |
268 ParNewGeneration& gen, | |
269 Generation& old_gen, | |
270 ObjToScanQueueSet& queue_set, | |
695 | 271 GrowableArray<oop>** overflow_stacks_, |
0 | 272 size_t desired_plab_sz, |
273 ParallelTaskTerminator& term); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
274 inline ParScanThreadState& thread_state(int i); |
0 | 275 int pushes() { return _pushes; } |
276 int pops() { return _pops; } | |
277 int steals() { return _steals; } | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
278 void reset(bool promotion_failed); |
0 | 279 void flush(); |
280 private: | |
281 ParallelTaskTerminator& _term; | |
282 ParNewGeneration& _gen; | |
283 Generation& _next_gen; | |
284 // staticstics | |
285 int _pushes; | |
286 int _pops; | |
287 int _steals; | |
288 }; | |
289 | |
290 | |
291 ParScanThreadStateSet::ParScanThreadStateSet( | |
292 int num_threads, Space& to_space, ParNewGeneration& gen, | |
293 Generation& old_gen, ObjToScanQueueSet& queue_set, | |
695 | 294 GrowableArray<oop>** overflow_stack_set_, |
0 | 295 size_t desired_plab_sz, ParallelTaskTerminator& term) |
296 : ResourceArray(sizeof(ParScanThreadState), num_threads), | |
297 _gen(gen), _next_gen(old_gen), _term(term), | |
298 _pushes(0), _pops(0), _steals(0) | |
299 { | |
300 assert(num_threads > 0, "sanity check!"); | |
301 // Initialize states. | |
302 for (int i = 0; i < num_threads; ++i) { | |
303 new ((ParScanThreadState*)_data + i) | |
304 ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set, | |
695 | 305 overflow_stack_set_, desired_plab_sz, term); |
0 | 306 } |
307 } | |
308 | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
309 inline ParScanThreadState& ParScanThreadStateSet::thread_state(int i) |
0 | 310 { |
311 assert(i >= 0 && i < length(), "sanity check!"); | |
312 return ((ParScanThreadState*)_data)[i]; | |
313 } | |
314 | |
315 | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
316 void ParScanThreadStateSet::reset(bool promotion_failed) |
0 | 317 { |
318 _term.reset_for_reuse(); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
319 if (promotion_failed) { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
320 for (int i = 0; i < length(); ++i) { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
321 thread_state(i).print_and_clear_promotion_failure_size(); |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
322 } |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
323 } |
0 | 324 } |
325 | |
326 void ParScanThreadStateSet::flush() | |
327 { | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
328 // Work in this loop should be kept as lightweight as |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
329 // possible since this might otherwise become a bottleneck |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
330 // to scaling. Should we add heavy-weight work into this |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
331 // loop, consider parallelizing the loop into the worker threads. |
0 | 332 for (int i = 0; i < length(); ++i) { |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
333 ParScanThreadState& par_scan_state = thread_state(i); |
0 | 334 |
335 // Flush stats related to To-space PLAB activity and | |
336 // retire the last buffer. | |
337 par_scan_state.to_space_alloc_buffer()-> | |
338 flush_stats_and_retire(_gen.plab_stats(), | |
339 false /* !retain */); | |
340 | |
341 // Every thread has its own age table. We need to merge | |
342 // them all into one. | |
343 ageTable *local_table = par_scan_state.age_table(); | |
344 _gen.age_table()->merge(local_table); | |
345 | |
346 // Inform old gen that we're done. | |
347 _next_gen.par_promote_alloc_done(i); | |
348 _next_gen.par_oop_since_save_marks_iterate_done(i); | |
349 | |
350 // Flush stats related to work queue activity (push/pop/steal) | |
351 // This could conceivably become a bottleneck; if so, we'll put the | |
352 // stat's gathering under the flag. | |
353 if (PAR_STATS_ENABLED) { | |
354 _pushes += par_scan_state.pushes(); | |
355 _pops += par_scan_state.pops(); | |
356 _steals += par_scan_state.steals(); | |
357 if (ParallelGCVerbose) { | |
358 gclog_or_tty->print("Thread %d complete:\n" | |
359 " Pushes: %7d Pops: %7d Steals %7d (in %d attempts)\n", | |
360 i, par_scan_state.pushes(), par_scan_state.pops(), | |
361 par_scan_state.steals(), par_scan_state.steal_attempts()); | |
362 if (par_scan_state.overflow_pushes() > 0 || | |
363 par_scan_state.overflow_refills() > 0) { | |
364 gclog_or_tty->print(" Overflow pushes: %7d " | |
365 "Overflow refills: %7d for %d objs.\n", | |
366 par_scan_state.overflow_pushes(), | |
367 par_scan_state.overflow_refills(), | |
368 par_scan_state.overflow_refill_objs()); | |
369 } | |
370 | |
371 double elapsed = par_scan_state.elapsed(); | |
372 double strong_roots = par_scan_state.strong_roots_time(); | |
373 double term = par_scan_state.term_time(); | |
374 gclog_or_tty->print( | |
375 " Elapsed: %7.2f ms.\n" | |
376 " Strong roots: %7.2f ms (%6.2f%%)\n" | |
377 " Termination: %7.2f ms (%6.2f%%) (in %d entries)\n", | |
378 elapsed * 1000.0, | |
379 strong_roots * 1000.0, (strong_roots*100.0/elapsed), | |
380 term * 1000.0, (term*100.0/elapsed), | |
381 par_scan_state.term_attempts()); | |
382 } | |
383 } | |
384 } | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
385 if (UseConcMarkSweepGC && ParallelGCThreads > 0) { |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
386 // We need to call this even when ResizeOldPLAB is disabled |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
387 // so as to avoid breaking some asserts. While we may be able |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
388 // to avoid this by reorganizing the code a bit, I am loathe |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
389 // to do that unless we find cases where ergo leads to bad |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
390 // performance. |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
391 CFLS_LAB::compute_desired_plab_size(); |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
392 } |
0 | 393 } |
394 | |
395 ParScanClosure::ParScanClosure(ParNewGeneration* g, | |
396 ParScanThreadState* par_scan_state) : | |
397 OopsInGenClosure(g), _par_scan_state(par_scan_state), _g(g) | |
398 { | |
399 assert(_g->level() == 0, "Optimized for youngest generation"); | |
400 _boundary = _g->reserved().end(); | |
401 } | |
402 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
403 void ParScanWithBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, true, false); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
404 void ParScanWithBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, true, false); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
405 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
406 void ParScanWithoutBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, false, false); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
407 void ParScanWithoutBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, false, false); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
408 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
409 void ParRootScanWithBarrierTwoGensClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, true, true); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
410 void ParRootScanWithBarrierTwoGensClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, true, true); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
411 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
412 void ParRootScanWithoutBarrierClosure::do_oop(oop* p) { ParScanClosure::do_oop_work(p, false, true); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
413 void ParRootScanWithoutBarrierClosure::do_oop(narrowOop* p) { ParScanClosure::do_oop_work(p, false, true); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
414 |
0 | 415 ParScanWeakRefClosure::ParScanWeakRefClosure(ParNewGeneration* g, |
416 ParScanThreadState* par_scan_state) | |
417 : ScanWeakRefClosure(g), _par_scan_state(par_scan_state) | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
418 {} |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
419 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
420 void ParScanWeakRefClosure::do_oop(oop* p) { ParScanWeakRefClosure::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
421 void ParScanWeakRefClosure::do_oop(narrowOop* p) { ParScanWeakRefClosure::do_oop_work(p); } |
0 | 422 |
423 #ifdef WIN32 | |
424 #pragma warning(disable: 4786) /* identifier was truncated to '255' characters in the browser information */ | |
425 #endif | |
426 | |
427 ParEvacuateFollowersClosure::ParEvacuateFollowersClosure( | |
428 ParScanThreadState* par_scan_state_, | |
429 ParScanWithoutBarrierClosure* to_space_closure_, | |
430 ParScanWithBarrierClosure* old_gen_closure_, | |
431 ParRootScanWithoutBarrierClosure* to_space_root_closure_, | |
432 ParNewGeneration* par_gen_, | |
433 ParRootScanWithBarrierTwoGensClosure* old_gen_root_closure_, | |
434 ObjToScanQueueSet* task_queues_, | |
435 ParallelTaskTerminator* terminator_) : | |
436 | |
437 _par_scan_state(par_scan_state_), | |
438 _to_space_closure(to_space_closure_), | |
439 _old_gen_closure(old_gen_closure_), | |
440 _to_space_root_closure(to_space_root_closure_), | |
441 _old_gen_root_closure(old_gen_root_closure_), | |
442 _par_gen(par_gen_), | |
443 _task_queues(task_queues_), | |
444 _terminator(terminator_) | |
445 {} | |
446 | |
447 void ParEvacuateFollowersClosure::do_void() { | |
448 ObjToScanQueue* work_q = par_scan_state()->work_queue(); | |
449 | |
450 while (true) { | |
451 | |
452 // Scan to-space and old-gen objs until we run out of both. | |
453 oop obj_to_scan; | |
454 par_scan_state()->trim_queues(0); | |
455 | |
456 // We have no local work, attempt to steal from other threads. | |
457 | |
458 // attempt to steal work from promoted. | |
459 par_scan_state()->note_steal_attempt(); | |
460 if (task_queues()->steal(par_scan_state()->thread_num(), | |
461 par_scan_state()->hash_seed(), | |
462 obj_to_scan)) { | |
463 par_scan_state()->note_steal(); | |
464 bool res = work_q->push(obj_to_scan); | |
465 assert(res, "Empty queue should have room for a push."); | |
466 | |
467 par_scan_state()->note_push(); | |
468 // if successful, goto Start. | |
469 continue; | |
470 | |
471 // try global overflow list. | |
472 } else if (par_gen()->take_from_overflow_list(par_scan_state())) { | |
473 continue; | |
474 } | |
475 | |
476 // Otherwise, offer termination. | |
477 par_scan_state()->start_term_time(); | |
478 if (terminator()->offer_termination()) break; | |
479 par_scan_state()->end_term_time(); | |
480 } | |
534 | 481 assert(par_gen()->_overflow_list == NULL && par_gen()->_num_par_pushes == 0, |
482 "Broken overflow list?"); | |
0 | 483 // Finish the last termination pause. |
484 par_scan_state()->end_term_time(); | |
485 } | |
486 | |
487 ParNewGenTask::ParNewGenTask(ParNewGeneration* gen, Generation* next_gen, | |
488 HeapWord* young_old_boundary, ParScanThreadStateSet* state_set) : | |
489 AbstractGangTask("ParNewGeneration collection"), | |
490 _gen(gen), _next_gen(next_gen), | |
491 _young_old_boundary(young_old_boundary), | |
492 _state_set(state_set) | |
493 {} | |
494 | |
495 void ParNewGenTask::work(int i) { | |
496 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
497 // Since this is being done in a separate thread, need new resource | |
498 // and handle marks. | |
499 ResourceMark rm; | |
500 HandleMark hm; | |
501 // We would need multiple old-gen queues otherwise. | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
502 assert(gch->n_gens() == 2, "Par young collection currently only works with one older gen."); |
0 | 503 |
504 Generation* old_gen = gch->next_gen(_gen); | |
505 | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
506 ParScanThreadState& par_scan_state = _state_set->thread_state(i); |
0 | 507 par_scan_state.set_young_old_boundary(_young_old_boundary); |
508 | |
509 par_scan_state.start_strong_roots(); | |
510 gch->gen_process_strong_roots(_gen->level(), | |
989
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
511 true, // Process younger gens, if any, |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
512 // as strong roots. |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
513 false, // no scope; this is parallel code |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
514 false, // not collecting perm generation. |
0 | 515 SharedHeap::SO_AllClasses, |
989
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
516 &par_scan_state.to_space_root_closure(), |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
517 true, // walk *all* scavengable nmethods |
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
518 &par_scan_state.older_gen_closure()); |
0 | 519 par_scan_state.end_strong_roots(); |
520 | |
521 // "evacuate followers". | |
522 par_scan_state.evacuate_followers_closure().do_void(); | |
523 } | |
524 | |
525 #ifdef _MSC_VER | |
526 #pragma warning( push ) | |
527 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list | |
528 #endif | |
529 ParNewGeneration:: | |
530 ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level) | |
531 : DefNewGeneration(rs, initial_byte_size, level, "PCopy"), | |
532 _overflow_list(NULL), | |
533 _is_alive_closure(this), | |
534 _plab_stats(YoungPLABSize, PLABWeight) | |
535 { | |
534 | 536 NOT_PRODUCT(_overflow_counter = ParGCWorkQueueOverflowInterval;) |
537 NOT_PRODUCT(_num_par_pushes = 0;) | |
0 | 538 _task_queues = new ObjToScanQueueSet(ParallelGCThreads); |
539 guarantee(_task_queues != NULL, "task_queues allocation failure."); | |
540 | |
541 for (uint i1 = 0; i1 < ParallelGCThreads; i1++) { | |
542 ObjToScanQueuePadded *q_padded = new ObjToScanQueuePadded(); | |
543 guarantee(q_padded != NULL, "work_queue Allocation failure."); | |
544 | |
545 _task_queues->register_queue(i1, &q_padded->work_queue); | |
546 } | |
547 | |
548 for (uint i2 = 0; i2 < ParallelGCThreads; i2++) | |
549 _task_queues->queue(i2)->initialize(); | |
550 | |
695 | 551 _overflow_stacks = NEW_C_HEAP_ARRAY(GrowableArray<oop>*, ParallelGCThreads); |
552 guarantee(_overflow_stacks != NULL, "Overflow stack set allocation failure"); | |
553 for (uint i = 0; i < ParallelGCThreads; i++) { | |
554 if (ParGCUseLocalOverflow) { | |
555 _overflow_stacks[i] = new (ResourceObj::C_HEAP) GrowableArray<oop>(512, true); | |
556 guarantee(_overflow_stacks[i] != NULL, "Overflow Stack allocation failure."); | |
557 } else { | |
558 _overflow_stacks[i] = NULL; | |
559 } | |
560 } | |
561 | |
0 | 562 if (UsePerfData) { |
563 EXCEPTION_MARK; | |
564 ResourceMark rm; | |
565 | |
566 const char* cname = | |
567 PerfDataManager::counter_name(_gen_counters->name_space(), "threads"); | |
568 PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, | |
569 ParallelGCThreads, CHECK); | |
570 } | |
571 } | |
572 #ifdef _MSC_VER | |
573 #pragma warning( pop ) | |
574 #endif | |
575 | |
576 // ParNewGeneration:: | |
577 ParKeepAliveClosure::ParKeepAliveClosure(ParScanWeakRefClosure* cl) : | |
578 DefNewGeneration::KeepAliveClosure(cl), _par_cl(cl) {} | |
579 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
580 template <class T> |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
581 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop_work(T* p) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
582 #ifdef ASSERT |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
583 { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
584 assert(!oopDesc::is_null(*p), "expected non-null ref"); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
585 oop obj = oopDesc::load_decode_heap_oop_not_null(p); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
586 // We never expect to see a null reference being processed |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
587 // as a weak reference. |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
588 assert(obj->is_oop(), "expected an oop while scanning weak refs"); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
589 } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
590 #endif // ASSERT |
0 | 591 |
592 _par_cl->do_oop_nv(p); | |
593 | |
594 if (Universe::heap()->is_in_reserved(p)) { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
595 oop obj = oopDesc::load_decode_heap_oop_not_null(p); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
596 _rs->write_ref_field_gc_par(p, obj); |
0 | 597 } |
598 } | |
599 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
600 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop(oop* p) { ParKeepAliveClosure::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
601 void /*ParNewGeneration::*/ParKeepAliveClosure::do_oop(narrowOop* p) { ParKeepAliveClosure::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
602 |
0 | 603 // ParNewGeneration:: |
604 KeepAliveClosure::KeepAliveClosure(ScanWeakRefClosure* cl) : | |
605 DefNewGeneration::KeepAliveClosure(cl) {} | |
606 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
607 template <class T> |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
608 void /*ParNewGeneration::*/KeepAliveClosure::do_oop_work(T* p) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
609 #ifdef ASSERT |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
610 { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
611 assert(!oopDesc::is_null(*p), "expected non-null ref"); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
612 oop obj = oopDesc::load_decode_heap_oop_not_null(p); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
613 // We never expect to see a null reference being processed |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
614 // as a weak reference. |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
615 assert(obj->is_oop(), "expected an oop while scanning weak refs"); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
616 } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
617 #endif // ASSERT |
0 | 618 |
619 _cl->do_oop_nv(p); | |
620 | |
621 if (Universe::heap()->is_in_reserved(p)) { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
622 oop obj = oopDesc::load_decode_heap_oop_not_null(p); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
623 _rs->write_ref_field_gc_par(p, obj); |
0 | 624 } |
625 } | |
626 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
627 void /*ParNewGeneration::*/KeepAliveClosure::do_oop(oop* p) { KeepAliveClosure::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
628 void /*ParNewGeneration::*/KeepAliveClosure::do_oop(narrowOop* p) { KeepAliveClosure::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
629 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
630 template <class T> void ScanClosureWithParBarrier::do_oop_work(T* p) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
631 T heap_oop = oopDesc::load_heap_oop(p); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
632 if (!oopDesc::is_null(heap_oop)) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
633 oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); |
0 | 634 if ((HeapWord*)obj < _boundary) { |
635 assert(!_g->to()->is_in_reserved(obj), "Scanning field twice?"); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
636 oop new_obj = obj->is_forwarded() |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
637 ? obj->forwardee() |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
638 : _g->DefNewGeneration::copy_to_survivor_space(obj); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
639 oopDesc::encode_store_heap_oop_not_null(p, new_obj); |
0 | 640 } |
641 if (_gc_barrier) { | |
642 // If p points to a younger generation, mark the card. | |
643 if ((HeapWord*)obj < _gen_boundary) { | |
644 _rs->write_ref_field_gc_par(p, obj); | |
645 } | |
646 } | |
647 } | |
648 } | |
649 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
650 void ScanClosureWithParBarrier::do_oop(oop* p) { ScanClosureWithParBarrier::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
651 void ScanClosureWithParBarrier::do_oop(narrowOop* p) { ScanClosureWithParBarrier::do_oop_work(p); } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
6
diff
changeset
|
652 |
0 | 653 class ParNewRefProcTaskProxy: public AbstractGangTask { |
654 typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; | |
655 public: | |
656 ParNewRefProcTaskProxy(ProcessTask& task, ParNewGeneration& gen, | |
657 Generation& next_gen, | |
658 HeapWord* young_old_boundary, | |
659 ParScanThreadStateSet& state_set); | |
660 | |
661 private: | |
662 virtual void work(int i); | |
663 | |
664 private: | |
665 ParNewGeneration& _gen; | |
666 ProcessTask& _task; | |
667 Generation& _next_gen; | |
668 HeapWord* _young_old_boundary; | |
669 ParScanThreadStateSet& _state_set; | |
670 }; | |
671 | |
672 ParNewRefProcTaskProxy::ParNewRefProcTaskProxy( | |
673 ProcessTask& task, ParNewGeneration& gen, | |
674 Generation& next_gen, | |
675 HeapWord* young_old_boundary, | |
676 ParScanThreadStateSet& state_set) | |
677 : AbstractGangTask("ParNewGeneration parallel reference processing"), | |
678 _gen(gen), | |
679 _task(task), | |
680 _next_gen(next_gen), | |
681 _young_old_boundary(young_old_boundary), | |
682 _state_set(state_set) | |
683 { | |
684 } | |
685 | |
686 void ParNewRefProcTaskProxy::work(int i) | |
687 { | |
688 ResourceMark rm; | |
689 HandleMark hm; | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
690 ParScanThreadState& par_scan_state = _state_set.thread_state(i); |
0 | 691 par_scan_state.set_young_old_boundary(_young_old_boundary); |
692 _task.work(i, par_scan_state.is_alive_closure(), | |
693 par_scan_state.keep_alive_closure(), | |
694 par_scan_state.evacuate_followers_closure()); | |
695 } | |
696 | |
697 class ParNewRefEnqueueTaskProxy: public AbstractGangTask { | |
698 typedef AbstractRefProcTaskExecutor::EnqueueTask EnqueueTask; | |
699 EnqueueTask& _task; | |
700 | |
701 public: | |
702 ParNewRefEnqueueTaskProxy(EnqueueTask& task) | |
703 : AbstractGangTask("ParNewGeneration parallel reference enqueue"), | |
704 _task(task) | |
705 { } | |
706 | |
707 virtual void work(int i) | |
708 { | |
709 _task.work(i); | |
710 } | |
711 }; | |
712 | |
713 | |
714 void ParNewRefProcTaskExecutor::execute(ProcessTask& task) | |
715 { | |
716 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
717 assert(gch->kind() == CollectedHeap::GenCollectedHeap, | |
718 "not a generational heap"); | |
719 WorkGang* workers = gch->workers(); | |
720 assert(workers != NULL, "Need parallel worker threads."); | |
721 ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(), | |
722 _generation.reserved().end(), _state_set); | |
723 workers->run_task(&rp_task); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
724 _state_set.reset(_generation.promotion_failed()); |
0 | 725 } |
726 | |
727 void ParNewRefProcTaskExecutor::execute(EnqueueTask& task) | |
728 { | |
729 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
730 WorkGang* workers = gch->workers(); | |
731 assert(workers != NULL, "Need parallel worker threads."); | |
732 ParNewRefEnqueueTaskProxy enq_task(task); | |
733 workers->run_task(&enq_task); | |
734 } | |
735 | |
736 void ParNewRefProcTaskExecutor::set_single_threaded_mode() | |
737 { | |
738 _state_set.flush(); | |
739 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
740 gch->set_par_threads(0); // 0 ==> non-parallel. | |
741 gch->save_marks(); | |
742 } | |
743 | |
744 ScanClosureWithParBarrier:: | |
745 ScanClosureWithParBarrier(ParNewGeneration* g, bool gc_barrier) : | |
746 ScanClosure(g, gc_barrier) {} | |
747 | |
748 EvacuateFollowersClosureGeneral:: | |
749 EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, int level, | |
750 OopsInGenClosure* cur, | |
751 OopsInGenClosure* older) : | |
752 _gch(gch), _level(level), | |
753 _scan_cur_or_nonheap(cur), _scan_older(older) | |
754 {} | |
755 | |
756 void EvacuateFollowersClosureGeneral::do_void() { | |
757 do { | |
758 // Beware: this call will lead to closure applications via virtual | |
759 // calls. | |
760 _gch->oop_since_save_marks_iterate(_level, | |
761 _scan_cur_or_nonheap, | |
762 _scan_older); | |
763 } while (!_gch->no_allocs_since_save_marks(_level)); | |
764 } | |
765 | |
766 | |
767 bool ParNewGeneration::_avoid_promotion_undo = false; | |
768 | |
769 void ParNewGeneration::adjust_desired_tenuring_threshold() { | |
770 // Set the desired survivor size to half the real survivor space | |
771 _tenuring_threshold = | |
772 age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize); | |
773 } | |
774 | |
775 // A Generation that does parallel young-gen collection. | |
776 | |
777 void ParNewGeneration::collect(bool full, | |
778 bool clear_all_soft_refs, | |
779 size_t size, | |
780 bool is_tlab) { | |
781 assert(full || size > 0, "otherwise we don't want to collect"); | |
782 GenCollectedHeap* gch = GenCollectedHeap::heap(); | |
783 assert(gch->kind() == CollectedHeap::GenCollectedHeap, | |
784 "not a CMS generational heap"); | |
785 AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy(); | |
786 WorkGang* workers = gch->workers(); | |
787 _next_gen = gch->next_gen(this); | |
788 assert(_next_gen != NULL, | |
789 "This must be the youngest gen, and not the only gen"); | |
790 assert(gch->n_gens() == 2, | |
791 "Par collection currently only works with single older gen."); | |
792 // Do we have to avoid promotion_undo? | |
793 if (gch->collector_policy()->is_concurrent_mark_sweep_policy()) { | |
794 set_avoid_promotion_undo(true); | |
795 } | |
796 | |
797 // If the next generation is too full to accomodate worst-case promotion | |
798 // from this generation, pass on collection; let the next generation | |
799 // do it. | |
800 if (!collection_attempt_is_safe()) { | |
801 gch->set_incremental_collection_will_fail(); | |
802 return; | |
803 } | |
804 assert(to()->is_empty(), "Else not collection_attempt_is_safe"); | |
805 | |
806 init_assuming_no_promotion_failure(); | |
807 | |
808 if (UseAdaptiveSizePolicy) { | |
809 set_survivor_overflow(false); | |
810 size_policy->minor_collection_begin(); | |
811 } | |
812 | |
813 TraceTime t1("GC", PrintGC && !PrintGCDetails, true, gclog_or_tty); | |
814 // Capture heap used before collection (for printing). | |
815 size_t gch_prev_used = gch->used(); | |
816 | |
817 SpecializationStats::clear(); | |
818 | |
819 age_table()->clear(); | |
263
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
820 to()->clear(SpaceDecorator::Mangle); |
0 | 821 |
822 gch->save_marks(); | |
823 assert(workers != NULL, "Need parallel worker threads."); | |
824 ParallelTaskTerminator _term(workers->total_workers(), task_queues()); | |
825 ParScanThreadStateSet thread_state_set(workers->total_workers(), | |
826 *to(), *this, *_next_gen, *task_queues(), | |
695 | 827 _overflow_stacks, desired_plab_sz(), _term); |
0 | 828 |
829 ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); | |
830 int n_workers = workers->total_workers(); | |
831 gch->set_par_threads(n_workers); | |
832 gch->rem_set()->prepare_for_younger_refs_iterate(true); | |
833 // It turns out that even when we're using 1 thread, doing the work in a | |
834 // separate thread causes wide variance in run times. We can't help this | |
835 // in the multi-threaded case, but we special-case n=1 here to get | |
836 // repeatable measurements of the 1-thread overhead of the parallel code. | |
837 if (n_workers > 1) { | |
989
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
838 GenCollectedHeap::StrongRootsScope srs(gch); |
0 | 839 workers->run_task(&tsk); |
840 } else { | |
989
148e5441d916
6863023: need non-perm oops in code cache for JSR 292
jrose
parents:
695
diff
changeset
|
841 GenCollectedHeap::StrongRootsScope srs(gch); |
0 | 842 tsk.work(0); |
843 } | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
844 thread_state_set.reset(promotion_failed()); |
0 | 845 |
846 if (PAR_STATS_ENABLED && ParallelGCVerbose) { | |
847 gclog_or_tty->print("Thread totals:\n" | |
848 " Pushes: %7d Pops: %7d Steals %7d (sum = %7d).\n", | |
849 thread_state_set.pushes(), thread_state_set.pops(), | |
850 thread_state_set.steals(), | |
851 thread_state_set.pops()+thread_state_set.steals()); | |
852 } | |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
853 assert(thread_state_set.pushes() == thread_state_set.pops() |
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
854 + thread_state_set.steals(), |
0 | 855 "Or else the queues are leaky."); |
856 | |
857 // Process (weak) reference objects found during scavenge. | |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
858 ReferenceProcessor* rp = ref_processor(); |
0 | 859 IsAliveClosure is_alive(this); |
860 ScanWeakRefClosure scan_weak_ref(this); | |
861 KeepAliveClosure keep_alive(&scan_weak_ref); | |
862 ScanClosure scan_without_gc_barrier(this, false); | |
863 ScanClosureWithParBarrier scan_with_gc_barrier(this, true); | |
864 set_promo_failure_scan_stack_closure(&scan_without_gc_barrier); | |
865 EvacuateFollowersClosureGeneral evacuate_followers(gch, _level, | |
866 &scan_without_gc_barrier, &scan_with_gc_barrier); | |
457
27a80744a83b
6778647: snap(), snap_policy() should be renamed setup(), setup_policy()
ysr
parents:
454
diff
changeset
|
867 rp->setup_policy(clear_all_soft_refs); |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
868 if (rp->processing_is_mt()) { |
0 | 869 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
870 rp->process_discovered_references(&is_alive, &keep_alive, |
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
871 &evacuate_followers, &task_executor); |
0 | 872 } else { |
873 thread_state_set.flush(); | |
874 gch->set_par_threads(0); // 0 ==> non-parallel. | |
875 gch->save_marks(); | |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
876 rp->process_discovered_references(&is_alive, &keep_alive, |
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
877 &evacuate_followers, NULL); |
0 | 878 } |
879 if (!promotion_failed()) { | |
880 // Swap the survivor spaces. | |
263
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
881 eden()->clear(SpaceDecorator::Mangle); |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
882 from()->clear(SpaceDecorator::Mangle); |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
883 if (ZapUnusedHeapArea) { |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
884 // This is now done here because of the piece-meal mangling which |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
885 // can check for valid mangling at intermediate points in the |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
886 // collection(s). When a minor collection fails to collect |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
887 // sufficient space resizing of the young generation can occur |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
888 // an redistribute the spaces in the young generation. Mangle |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
889 // here so that unzapped regions don't get distributed to |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
890 // other spaces. |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
891 to()->mangle_unused_area(); |
12eea04c8b06
6672698: mangle_unused_area() should not remangle the entire heap at each collection.
jmasa
parents:
167
diff
changeset
|
892 } |
0 | 893 swap_spaces(); |
894 | |
895 assert(to()->is_empty(), "to space should be empty now"); | |
896 } else { | |
897 assert(HandlePromotionFailure, | |
898 "Should only be here if promotion failure handling is on"); | |
899 if (_promo_failure_scan_stack != NULL) { | |
900 // Can be non-null because of reference processing. | |
901 // Free stack with its elements. | |
902 delete _promo_failure_scan_stack; | |
903 _promo_failure_scan_stack = NULL; | |
904 } | |
905 remove_forwarding_pointers(); | |
906 if (PrintGCDetails) { | |
907 gclog_or_tty->print(" (promotion failed)"); | |
908 } | |
909 // All the spaces are in play for mark-sweep. | |
910 swap_spaces(); // Make life simpler for CMS || rescan; see 6483690. | |
911 from()->set_next_compaction_space(to()); | |
912 gch->set_incremental_collection_will_fail(); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
913 // Inform the next generation that a promotion failure occurred. |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
914 _next_gen->promotion_failure_occurred(); |
6
73e96e5c30df
6624765: Guarantee failure "Unexpected dirty card found"
jmasa
parents:
0
diff
changeset
|
915 |
73e96e5c30df
6624765: Guarantee failure "Unexpected dirty card found"
jmasa
parents:
0
diff
changeset
|
916 // Reset the PromotionFailureALot counters. |
73e96e5c30df
6624765: Guarantee failure "Unexpected dirty card found"
jmasa
parents:
0
diff
changeset
|
917 NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();) |
0 | 918 } |
919 // set new iteration safe limit for the survivor spaces | |
920 from()->set_concurrent_iteration_safe_limit(from()->top()); | |
921 to()->set_concurrent_iteration_safe_limit(to()->top()); | |
922 | |
923 adjust_desired_tenuring_threshold(); | |
924 if (ResizePLAB) { | |
925 plab_stats()->adjust_desired_plab_sz(); | |
926 } | |
927 | |
928 if (PrintGC && !PrintGCDetails) { | |
929 gch->print_heap_change(gch_prev_used); | |
930 } | |
931 | |
932 if (UseAdaptiveSizePolicy) { | |
933 size_policy->minor_collection_end(gch->gc_cause()); | |
934 size_policy->avg_survived()->sample(from()->used()); | |
935 } | |
936 | |
937 update_time_of_last_gc(os::javaTimeMillis()); | |
938 | |
939 SpecializationStats::print(); | |
940 | |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
941 rp->set_enqueuing_is_done(true); |
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
942 if (rp->processing_is_mt()) { |
0 | 943 ParNewRefProcTaskExecutor task_executor(*this, thread_state_set); |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
944 rp->enqueue_discovered_references(&task_executor); |
0 | 945 } else { |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
946 rp->enqueue_discovered_references(NULL); |
0 | 947 } |
453
c96030fff130
6684579: SoftReference processing can be made more efficient
ysr
parents:
269
diff
changeset
|
948 rp->verify_no_references_recorded(); |
0 | 949 } |
950 | |
951 static int sum; | |
952 void ParNewGeneration::waste_some_time() { | |
953 for (int i = 0; i < 100; i++) { | |
954 sum += i; | |
955 } | |
956 } | |
957 | |
958 static const oop ClaimedForwardPtr = oop(0x4); | |
959 | |
960 // Because of concurrency, there are times where an object for which | |
961 // "is_forwarded()" is true contains an "interim" forwarding pointer | |
962 // value. Such a value will soon be overwritten with a real value. | |
963 // This method requires "obj" to have a forwarding pointer, and waits, if | |
964 // necessary for a real one to be inserted, and returns it. | |
965 | |
966 oop ParNewGeneration::real_forwardee(oop obj) { | |
967 oop forward_ptr = obj->forwardee(); | |
968 if (forward_ptr != ClaimedForwardPtr) { | |
969 return forward_ptr; | |
970 } else { | |
971 return real_forwardee_slow(obj); | |
972 } | |
973 } | |
974 | |
975 oop ParNewGeneration::real_forwardee_slow(oop obj) { | |
976 // Spin-read if it is claimed but not yet written by another thread. | |
977 oop forward_ptr = obj->forwardee(); | |
978 while (forward_ptr == ClaimedForwardPtr) { | |
979 waste_some_time(); | |
980 assert(obj->is_forwarded(), "precondition"); | |
981 forward_ptr = obj->forwardee(); | |
982 } | |
983 return forward_ptr; | |
984 } | |
985 | |
986 #ifdef ASSERT | |
987 bool ParNewGeneration::is_legal_forward_ptr(oop p) { | |
988 return | |
989 (_avoid_promotion_undo && p == ClaimedForwardPtr) | |
990 || Universe::heap()->is_in_reserved(p); | |
991 } | |
992 #endif | |
993 | |
994 void ParNewGeneration::preserve_mark_if_necessary(oop obj, markOop m) { | |
995 if ((m != markOopDesc::prototype()) && | |
996 (!UseBiasedLocking || (m != markOopDesc::biased_locking_prototype()))) { | |
997 MutexLocker ml(ParGCRareEvent_lock); | |
998 DefNewGeneration::preserve_mark_if_necessary(obj, m); | |
999 } | |
1000 } | |
1001 | |
1002 // Multiple GC threads may try to promote an object. If the object | |
1003 // is successfully promoted, a forwarding pointer will be installed in | |
1004 // the object in the young generation. This method claims the right | |
1005 // to install the forwarding pointer before it copies the object, | |
1006 // thus avoiding the need to undo the copy as in | |
1007 // copy_to_survivor_space_avoiding_with_undo. | |
1008 | |
1009 oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo( | |
1010 ParScanThreadState* par_scan_state, oop old, size_t sz, markOop m) { | |
1011 // In the sequential version, this assert also says that the object is | |
1012 // not forwarded. That might not be the case here. It is the case that | |
1013 // the caller observed it to be not forwarded at some time in the past. | |
1014 assert(is_in_reserved(old), "shouldn't be scavenging this oop"); | |
1015 | |
1016 // The sequential code read "old->age()" below. That doesn't work here, | |
1017 // since the age is in the mark word, and that might be overwritten with | |
1018 // a forwarding pointer by a parallel thread. So we must save the mark | |
1019 // word in a local and then analyze it. | |
1020 oopDesc dummyOld; | |
1021 dummyOld.set_mark(m); | |
1022 assert(!dummyOld.is_forwarded(), | |
1023 "should not be called with forwarding pointer mark word."); | |
1024 | |
1025 oop new_obj = NULL; | |
1026 oop forward_ptr; | |
1027 | |
1028 // Try allocating obj in to-space (unless too old) | |
1029 if (dummyOld.age() < tenuring_threshold()) { | |
1030 new_obj = (oop)par_scan_state->alloc_in_to_space(sz); | |
1031 if (new_obj == NULL) { | |
1032 set_survivor_overflow(true); | |
1033 } | |
1034 } | |
1035 | |
1036 if (new_obj == NULL) { | |
1037 // Either to-space is full or we decided to promote | |
1038 // try allocating obj tenured | |
1039 | |
1040 // Attempt to install a null forwarding pointer (atomically), | |
1041 // to claim the right to install the real forwarding pointer. | |
1042 forward_ptr = old->forward_to_atomic(ClaimedForwardPtr); | |
1043 if (forward_ptr != NULL) { | |
1044 // someone else beat us to it. | |
1045 return real_forwardee(old); | |
1046 } | |
1047 | |
1048 new_obj = _next_gen->par_promote(par_scan_state->thread_num(), | |
1049 old, m, sz); | |
1050 | |
1051 if (new_obj == NULL) { | |
1052 if (!HandlePromotionFailure) { | |
1053 // A failed promotion likely means the MaxLiveObjectEvacuationRatio flag | |
1054 // is incorrectly set. In any case, its seriously wrong to be here! | |
1055 vm_exit_out_of_memory(sz*wordSize, "promotion"); | |
1056 } | |
1057 // promotion failed, forward to self | |
1058 _promotion_failed = true; | |
1059 new_obj = old; | |
1060 | |
1061 preserve_mark_if_necessary(old, m); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
1062 // Log the size of the maiden promotion failure |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
1063 par_scan_state->log_promotion_failure(sz); |
0 | 1064 } |
1065 | |
1066 old->forward_to(new_obj); | |
1067 forward_ptr = NULL; | |
1068 } else { | |
1069 // Is in to-space; do copying ourselves. | |
1070 Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz); | |
1071 forward_ptr = old->forward_to_atomic(new_obj); | |
1072 // Restore the mark word copied above. | |
1073 new_obj->set_mark(m); | |
1074 // Increment age if obj still in new generation | |
1075 new_obj->incr_age(); | |
1076 par_scan_state->age_table()->add(new_obj, sz); | |
1077 } | |
1078 assert(new_obj != NULL, "just checking"); | |
1079 | |
1080 if (forward_ptr == NULL) { | |
1081 oop obj_to_push = new_obj; | |
1082 if (par_scan_state->should_be_partially_scanned(obj_to_push, old)) { | |
1083 // Length field used as index of next element to be scanned. | |
1084 // Real length can be obtained from real_forwardee() | |
1085 arrayOop(old)->set_length(0); | |
1086 obj_to_push = old; | |
1087 assert(obj_to_push->is_forwarded() && obj_to_push->forwardee() != obj_to_push, | |
1088 "push forwarded object"); | |
1089 } | |
1090 // Push it on one of the queues of to-be-scanned objects. | |
534 | 1091 bool simulate_overflow = false; |
1092 NOT_PRODUCT( | |
1093 if (ParGCWorkQueueOverflowALot && should_simulate_overflow()) { | |
1094 // simulate a stack overflow | |
1095 simulate_overflow = true; | |
1096 } | |
1097 ) | |
1098 if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { | |
0 | 1099 // Add stats for overflow pushes. |
1100 if (Verbose && PrintGCDetails) { | |
1101 gclog_or_tty->print("queue overflow!\n"); | |
1102 } | |
534 | 1103 push_on_overflow_list(old, par_scan_state); |
0 | 1104 par_scan_state->note_overflow_push(); |
1105 } | |
1106 par_scan_state->note_push(); | |
1107 | |
1108 return new_obj; | |
1109 } | |
1110 | |
1111 // Oops. Someone beat us to it. Undo the allocation. Where did we | |
1112 // allocate it? | |
1113 if (is_in_reserved(new_obj)) { | |
1114 // Must be in to_space. | |
1115 assert(to()->is_in_reserved(new_obj), "Checking"); | |
1116 if (forward_ptr == ClaimedForwardPtr) { | |
1117 // Wait to get the real forwarding pointer value. | |
1118 forward_ptr = real_forwardee(old); | |
1119 } | |
1120 par_scan_state->undo_alloc_in_to_space((HeapWord*)new_obj, sz); | |
1121 } | |
1122 | |
1123 return forward_ptr; | |
1124 } | |
1125 | |
1126 | |
1127 // Multiple GC threads may try to promote the same object. If two | |
1128 // or more GC threads copy the object, only one wins the race to install | |
1129 // the forwarding pointer. The other threads have to undo their copy. | |
1130 | |
1131 oop ParNewGeneration::copy_to_survivor_space_with_undo( | |
1132 ParScanThreadState* par_scan_state, oop old, size_t sz, markOop m) { | |
1133 | |
1134 // In the sequential version, this assert also says that the object is | |
1135 // not forwarded. That might not be the case here. It is the case that | |
1136 // the caller observed it to be not forwarded at some time in the past. | |
1137 assert(is_in_reserved(old), "shouldn't be scavenging this oop"); | |
1138 | |
1139 // The sequential code read "old->age()" below. That doesn't work here, | |
1140 // since the age is in the mark word, and that might be overwritten with | |
1141 // a forwarding pointer by a parallel thread. So we must save the mark | |
1142 // word here, install it in a local oopDesc, and then analyze it. | |
1143 oopDesc dummyOld; | |
1144 dummyOld.set_mark(m); | |
1145 assert(!dummyOld.is_forwarded(), | |
1146 "should not be called with forwarding pointer mark word."); | |
1147 | |
1148 bool failed_to_promote = false; | |
1149 oop new_obj = NULL; | |
1150 oop forward_ptr; | |
1151 | |
1152 // Try allocating obj in to-space (unless too old) | |
1153 if (dummyOld.age() < tenuring_threshold()) { | |
1154 new_obj = (oop)par_scan_state->alloc_in_to_space(sz); | |
1155 if (new_obj == NULL) { | |
1156 set_survivor_overflow(true); | |
1157 } | |
1158 } | |
1159 | |
1160 if (new_obj == NULL) { | |
1161 // Either to-space is full or we decided to promote | |
1162 // try allocating obj tenured | |
1163 new_obj = _next_gen->par_promote(par_scan_state->thread_num(), | |
1164 old, m, sz); | |
1165 | |
1166 if (new_obj == NULL) { | |
1167 if (!HandlePromotionFailure) { | |
1168 // A failed promotion likely means the MaxLiveObjectEvacuationRatio | |
1169 // flag is incorrectly set. In any case, its seriously wrong to be | |
1170 // here! | |
1171 vm_exit_out_of_memory(sz*wordSize, "promotion"); | |
1172 } | |
1173 // promotion failed, forward to self | |
1174 forward_ptr = old->forward_to_atomic(old); | |
1175 new_obj = old; | |
1176 | |
1177 if (forward_ptr != NULL) { | |
1178 return forward_ptr; // someone else succeeded | |
1179 } | |
1180 | |
1181 _promotion_failed = true; | |
1182 failed_to_promote = true; | |
1183 | |
1184 preserve_mark_if_necessary(old, m); | |
1145
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
1185 // Log the size of the maiden promotion failure |
e018e6884bd8
6631166: CMS: better heuristics when combatting fragmentation
ysr
parents:
989
diff
changeset
|
1186 par_scan_state->log_promotion_failure(sz); |
0 | 1187 } |
1188 } else { | |
1189 // Is in to-space; do copying ourselves. | |
1190 Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)new_obj, sz); | |
1191 // Restore the mark word copied above. | |
1192 new_obj->set_mark(m); | |
1193 // Increment age if new_obj still in new generation | |
1194 new_obj->incr_age(); | |
1195 par_scan_state->age_table()->add(new_obj, sz); | |
1196 } | |
1197 assert(new_obj != NULL, "just checking"); | |
1198 | |
1199 // Now attempt to install the forwarding pointer (atomically). | |
1200 // We have to copy the mark word before overwriting with forwarding | |
1201 // ptr, so we can restore it below in the copy. | |
1202 if (!failed_to_promote) { | |
1203 forward_ptr = old->forward_to_atomic(new_obj); | |
1204 } | |
1205 | |
1206 if (forward_ptr == NULL) { | |
1207 oop obj_to_push = new_obj; | |
1208 if (par_scan_state->should_be_partially_scanned(obj_to_push, old)) { | |
1209 // Length field used as index of next element to be scanned. | |
1210 // Real length can be obtained from real_forwardee() | |
1211 arrayOop(old)->set_length(0); | |
1212 obj_to_push = old; | |
1213 assert(obj_to_push->is_forwarded() && obj_to_push->forwardee() != obj_to_push, | |
1214 "push forwarded object"); | |
1215 } | |
1216 // Push it on one of the queues of to-be-scanned objects. | |
534 | 1217 bool simulate_overflow = false; |
1218 NOT_PRODUCT( | |
1219 if (ParGCWorkQueueOverflowALot && should_simulate_overflow()) { | |
1220 // simulate a stack overflow | |
1221 simulate_overflow = true; | |
1222 } | |
1223 ) | |
1224 if (simulate_overflow || !par_scan_state->work_queue()->push(obj_to_push)) { | |
0 | 1225 // Add stats for overflow pushes. |
534 | 1226 push_on_overflow_list(old, par_scan_state); |
0 | 1227 par_scan_state->note_overflow_push(); |
1228 } | |
1229 par_scan_state->note_push(); | |
1230 | |
1231 return new_obj; | |
1232 } | |
1233 | |
1234 // Oops. Someone beat us to it. Undo the allocation. Where did we | |
1235 // allocate it? | |
1236 if (is_in_reserved(new_obj)) { | |
1237 // Must be in to_space. | |
1238 assert(to()->is_in_reserved(new_obj), "Checking"); | |
1239 par_scan_state->undo_alloc_in_to_space((HeapWord*)new_obj, sz); | |
1240 } else { | |
1241 assert(!_avoid_promotion_undo, "Should not be here if avoiding."); | |
1242 _next_gen->par_promote_alloc_undo(par_scan_state->thread_num(), | |
1243 (HeapWord*)new_obj, sz); | |
1244 } | |
1245 | |
1246 return forward_ptr; | |
1247 } | |
1248 | |
534 | 1249 #ifndef PRODUCT |
1250 // It's OK to call this multi-threaded; the worst thing | |
1251 // that can happen is that we'll get a bunch of closely | |
1252 // spaced simulated oveflows, but that's OK, in fact | |
1253 // probably good as it would exercise the overflow code | |
1254 // under contention. | |
1255 bool ParNewGeneration::should_simulate_overflow() { | |
1256 if (_overflow_counter-- <= 0) { // just being defensive | |
1257 _overflow_counter = ParGCWorkQueueOverflowInterval; | |
1258 return true; | |
1259 } else { | |
1260 return false; | |
1261 } | |
1262 } | |
1263 #endif | |
1264 | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1265 // In case we are using compressed oops, we need to be careful. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1266 // If the object being pushed is an object array, then its length |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1267 // field keeps track of the "grey boundary" at which the next |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1268 // incremental scan will be done (see ParGCArrayScanChunk). |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1269 // When using compressed oops, this length field is kept in the |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1270 // lower 32 bits of the erstwhile klass word and cannot be used |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1271 // for the overflow chaining pointer (OCP below). As such the OCP |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1272 // would itself need to be compressed into the top 32-bits in this |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1273 // case. Unfortunately, see below, in the event that we have a |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1274 // promotion failure, the node to be pushed on the list can be |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1275 // outside of the Java heap, so the heap-based pointer compression |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1276 // would not work (we would have potential aliasing between C-heap |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1277 // and Java-heap pointers). For this reason, when using compressed |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1278 // oops, we simply use a worker-thread-local, non-shared overflow |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1279 // list in the form of a growable array, with a slightly different |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1280 // overflow stack draining strategy. If/when we start using fat |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1281 // stacks here, we can go back to using (fat) pointer chains |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1282 // (although some performance comparisons would be useful since |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1283 // single global lists have their own performance disadvantages |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1284 // as we were made painfully aware not long ago, see 6786503). |
534 | 1285 #define BUSY (oop(0x1aff1aff)) |
1286 void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) { | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1287 assert(is_in_reserved(from_space_obj), "Should be from this generation"); |
695 | 1288 if (ParGCUseLocalOverflow) { |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1289 // In the case of compressed oops, we use a private, not-shared |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1290 // overflow stack. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1291 par_scan_state->push_on_overflow_stack(from_space_obj); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1292 } else { |
695 | 1293 assert(!UseCompressedOops, "Error"); |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1294 // if the object has been forwarded to itself, then we cannot |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1295 // use the klass pointer for the linked list. Instead we have |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1296 // to allocate an oopDesc in the C-Heap and use that for the linked list. |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1297 // XXX This is horribly inefficient when a promotion failure occurs |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1298 // and should be fixed. XXX FIX ME !!! |
534 | 1299 #ifndef PRODUCT |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1300 Atomic::inc_ptr(&_num_par_pushes); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1301 assert(_num_par_pushes > 0, "Tautology"); |
534 | 1302 #endif |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1303 if (from_space_obj->forwardee() == from_space_obj) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1304 oopDesc* listhead = NEW_C_HEAP_ARRAY(oopDesc, 1); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1305 listhead->forward_to(from_space_obj); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1306 from_space_obj = listhead; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1307 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1308 oop observed_overflow_list = _overflow_list; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1309 oop cur_overflow_list; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1310 do { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1311 cur_overflow_list = observed_overflow_list; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1312 if (cur_overflow_list != BUSY) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1313 from_space_obj->set_klass_to_list_ptr(cur_overflow_list); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1314 } else { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1315 from_space_obj->set_klass_to_list_ptr(NULL); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1316 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1317 observed_overflow_list = |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1318 (oop)Atomic::cmpxchg_ptr(from_space_obj, &_overflow_list, cur_overflow_list); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1319 } while (cur_overflow_list != observed_overflow_list); |
0 | 1320 } |
1321 } | |
1322 | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1323 bool ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) { |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1324 bool res; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1325 |
695 | 1326 if (ParGCUseLocalOverflow) { |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1327 res = par_scan_state->take_from_overflow_stack(); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1328 } else { |
695 | 1329 assert(!UseCompressedOops, "Error"); |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1330 res = take_from_overflow_list_work(par_scan_state); |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1331 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1332 return res; |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1333 } |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1334 |
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1335 |
534 | 1336 // *NOTE*: The overflow list manipulation code here and |
1337 // in CMSCollector:: are very similar in shape, | |
1338 // except that in the CMS case we thread the objects | |
1339 // directly into the list via their mark word, and do | |
1340 // not need to deal with special cases below related | |
1341 // to chunking of object arrays and promotion failure | |
1342 // handling. | |
1343 // CR 6797058 has been filed to attempt consolidation of | |
1344 // the common code. | |
1345 // Because of the common code, if you make any changes in | |
1346 // the code below, please check the CMS version to see if | |
1347 // similar changes might be needed. | |
1348 // See CMSCollector::par_take_from_overflow_list() for | |
1349 // more extensive documentation comments. | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1350 bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan_state) { |
0 | 1351 ObjToScanQueue* work_q = par_scan_state->work_queue(); |
1352 // How many to take? | |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1353 size_t objsFromOverflow = MIN2((size_t)(work_q->max_elems() - work_q->size())/4, |
534 | 1354 (size_t)ParGCDesiredObjsFromOverflowList); |
0 | 1355 |
679
cea947c8a988
6819891: ParNew: Fix work queue overflow code to deal correctly with +UseCompressedOops
ysr
parents:
579
diff
changeset
|
1356 assert(par_scan_state->overflow_stack() == NULL, "Error"); |
695 | 1357 assert(!UseCompressedOops, "Error"); |
0 | 1358 if (_overflow_list == NULL) return false; |
1359 | |
1360 // Otherwise, there was something there; try claiming the list. | |
534 | 1361 oop prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); |
1362 // Trim off a prefix of at most objsFromOverflow items | |
1363 Thread* tid = Thread::current(); | |
1364 size_t spin_count = (size_t)ParallelGCThreads; | |
1365 size_t sleep_time_millis = MAX2((size_t)1, objsFromOverflow/100); | |
1366 for (size_t spin = 0; prefix == BUSY && spin < spin_count; spin++) { | |
1367 // someone grabbed it before we did ... | |
1368 // ... we spin for a short while... | |
1369 os::sleep(tid, sleep_time_millis, false); | |
1370 if (_overflow_list == NULL) { | |
1371 // nothing left to take | |
1372 return false; | |
1373 } else if (_overflow_list != BUSY) { | |
1374 // try and grab the prefix | |
1375 prefix = (oop)Atomic::xchg_ptr(BUSY, &_overflow_list); | |
1376 } | |
0 | 1377 } |
534 | 1378 if (prefix == NULL || prefix == BUSY) { |
1379 // Nothing to take or waited long enough | |
1380 if (prefix == NULL) { | |
1381 // Write back the NULL in case we overwrote it with BUSY above | |
1382 // and it is still the same value. | |
1383 (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); | |
1384 } | |
1385 return false; | |
1386 } | |
1387 assert(prefix != NULL && prefix != BUSY, "Error"); | |
1388 size_t i = 1; | |
0 | 1389 oop cur = prefix; |
167
feeb96a45707
6696264: assert("narrow oop can never be zero") for GCBasher & ParNewGC
coleenp
parents:
113
diff
changeset
|
1390 while (i < objsFromOverflow && cur->klass_or_null() != NULL) { |
0 | 1391 i++; cur = oop(cur->klass()); |
1392 } | |
1393 | |
1394 // Reattach remaining (suffix) to overflow list | |
534 | 1395 if (cur->klass_or_null() == NULL) { |
1396 // Write back the NULL in lieu of the BUSY we wrote | |
1397 // above and it is still the same value. | |
1398 if (_overflow_list == BUSY) { | |
1399 (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY); | |
0 | 1400 } |
534 | 1401 } else { |
1402 assert(cur->klass_or_null() != BUSY, "Error"); | |
1403 oop suffix = oop(cur->klass()); // suffix will be put back on global list | |
1404 cur->set_klass_to_list_ptr(NULL); // break off suffix | |
1405 // It's possible that the list is still in the empty(busy) state | |
1406 // we left it in a short while ago; in that case we may be | |
1407 // able to place back the suffix. | |
1408 oop observed_overflow_list = _overflow_list; | |
1409 oop cur_overflow_list = observed_overflow_list; | |
1410 bool attached = false; | |
1411 while (observed_overflow_list == BUSY || observed_overflow_list == NULL) { | |
1412 observed_overflow_list = | |
1413 (oop) Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list); | |
1414 if (cur_overflow_list == observed_overflow_list) { | |
1415 attached = true; | |
1416 break; | |
1417 } else cur_overflow_list = observed_overflow_list; | |
1418 } | |
1419 if (!attached) { | |
1420 // Too bad, someone else got in in between; we'll need to do a splice. | |
1421 // Find the last item of suffix list | |
1422 oop last = suffix; | |
1423 while (last->klass_or_null() != NULL) { | |
1424 last = oop(last->klass()); | |
1425 } | |
1426 // Atomically prepend suffix to current overflow list | |
1427 observed_overflow_list = _overflow_list; | |
1428 do { | |
1429 cur_overflow_list = observed_overflow_list; | |
1430 if (cur_overflow_list != BUSY) { | |
1431 // Do the splice ... | |
1432 last->set_klass_to_list_ptr(cur_overflow_list); | |
1433 } else { // cur_overflow_list == BUSY | |
1434 last->set_klass_to_list_ptr(NULL); | |
1435 } | |
1436 observed_overflow_list = | |
1437 (oop)Atomic::cmpxchg_ptr(suffix, &_overflow_list, cur_overflow_list); | |
1438 } while (cur_overflow_list != observed_overflow_list); | |
0 | 1439 } |
1440 } | |
1441 | |
1442 // Push objects on prefix list onto this thread's work queue | |
534 | 1443 assert(prefix != NULL && prefix != BUSY, "program logic"); |
0 | 1444 cur = prefix; |
534 | 1445 ssize_t n = 0; |
0 | 1446 while (cur != NULL) { |
1447 oop obj_to_push = cur->forwardee(); | |
454
df4305d4c1a1
6774607: SIGSEGV or (!is_null(v),"oop value can never be zero") assertion when running with CMS and COOPs
ysr
parents:
453
diff
changeset
|
1448 oop next = oop(cur->klass_or_null()); |
0 | 1449 cur->set_klass(obj_to_push->klass()); |
534 | 1450 // This may be an array object that is self-forwarded. In that case, the list pointer |
1451 // space, cur, is not in the Java heap, but rather in the C-heap and should be freed. | |
1452 if (!is_in_reserved(cur)) { | |
1453 // This can become a scaling bottleneck when there is work queue overflow coincident | |
1454 // with promotion failure. | |
1455 oopDesc* f = cur; | |
1456 FREE_C_HEAP_ARRAY(oopDesc, f); | |
1457 } else if (par_scan_state->should_be_partially_scanned(obj_to_push, cur)) { | |
0 | 1458 assert(arrayOop(cur)->length() == 0, "entire array remaining to be scanned"); |
534 | 1459 obj_to_push = cur; |
0 | 1460 } |
534 | 1461 bool ok = work_q->push(obj_to_push); |
1462 assert(ok, "Should have succeeded"); | |
0 | 1463 cur = next; |
1464 n++; | |
1465 } | |
1466 par_scan_state->note_overflow_refill(n); | |
534 | 1467 #ifndef PRODUCT |
1468 assert(_num_par_pushes >= n, "Too many pops?"); | |
1469 Atomic::add_ptr(-(intptr_t)n, &_num_par_pushes); | |
1470 #endif | |
0 | 1471 return true; |
1472 } | |
534 | 1473 #undef BUSY |
0 | 1474 |
1475 void ParNewGeneration::ref_processor_init() | |
1476 { | |
1477 if (_ref_processor == NULL) { | |
1478 // Allocate and initialize a reference processor | |
1479 _ref_processor = ReferenceProcessor::create_ref_processor( | |
1480 _reserved, // span | |
1481 refs_discovery_is_atomic(), // atomic_discovery | |
1482 refs_discovery_is_mt(), // mt_discovery | |
1483 NULL, // is_alive_non_header | |
1484 ParallelGCThreads, | |
1485 ParallelRefProcEnabled); | |
1486 } | |
1487 } | |
1488 | |
1489 const char* ParNewGeneration::name() const { | |
1490 return "par new generation"; | |
1491 } |