comparison src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp @ 1311:2a1472c30599

4396719: Mark Sweep stack overflow on deeply nested Object arrays Summary: Use an explicit stack for object arrays and process them in chunks. Reviewed-by: iveresov, apetrusenko
author jcoomes
date Wed, 03 Mar 2010 14:48:26 -0800
parents 89e0543e1737
children c385bf94cfb8
comparison
equal deleted inserted replaced
1289:d47555d7aca8 1311:2a1472c30599
26 #include "incls/_psCompactionManager.cpp.incl" 26 #include "incls/_psCompactionManager.cpp.incl"
27 27
28 PSOldGen* ParCompactionManager::_old_gen = NULL; 28 PSOldGen* ParCompactionManager::_old_gen = NULL;
29 ParCompactionManager** ParCompactionManager::_manager_array = NULL; 29 ParCompactionManager** ParCompactionManager::_manager_array = NULL;
30 OopTaskQueueSet* ParCompactionManager::_stack_array = NULL; 30 OopTaskQueueSet* ParCompactionManager::_stack_array = NULL;
31 ParCompactionManager::ObjArrayTaskQueueSet*
32 ParCompactionManager::_objarray_queues = NULL;
31 ObjectStartArray* ParCompactionManager::_start_array = NULL; 33 ObjectStartArray* ParCompactionManager::_start_array = NULL;
32 ParMarkBitMap* ParCompactionManager::_mark_bitmap = NULL; 34 ParMarkBitMap* ParCompactionManager::_mark_bitmap = NULL;
33 RegionTaskQueueSet* ParCompactionManager::_region_array = NULL; 35 RegionTaskQueueSet* ParCompactionManager::_region_array = NULL;
34 36
35 ParCompactionManager::ParCompactionManager() : 37 ParCompactionManager::ParCompactionManager() :
44 46
45 marking_stack()->initialize(); 47 marking_stack()->initialize();
46 48
47 // We want the overflow stack to be permanent 49 // We want the overflow stack to be permanent
48 _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray<oop>(10, true); 50 _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray<oop>(10, true);
51
52 _objarray_queue.initialize();
53 _objarray_overflow_stack =
54 new (ResourceObj::C_HEAP) ObjArrayOverflowStack(10, true);
55
49 #ifdef USE_RegionTaskQueueWithOverflow 56 #ifdef USE_RegionTaskQueueWithOverflow
50 region_stack()->initialize(); 57 region_stack()->initialize();
51 #else 58 #else
52 region_stack()->initialize(); 59 region_stack()->initialize();
53 60
67 74
68 } 75 }
69 76
70 ParCompactionManager::~ParCompactionManager() { 77 ParCompactionManager::~ParCompactionManager() {
71 delete _overflow_stack; 78 delete _overflow_stack;
79 delete _objarray_overflow_stack;
72 delete _revisit_klass_stack; 80 delete _revisit_klass_stack;
73 delete _revisit_mdo_stack; 81 delete _revisit_mdo_stack;
74 // _manager_array and _stack_array are statics 82 // _manager_array and _stack_array are statics
75 // shared with all instances of ParCompactionManager 83 // shared with all instances of ParCompactionManager
76 // should not be deallocated. 84 // should not be deallocated.
84 92
85 uint parallel_gc_threads = PSParallelCompact::gc_task_manager()->workers(); 93 uint parallel_gc_threads = PSParallelCompact::gc_task_manager()->workers();
86 94
87 assert(_manager_array == NULL, "Attempt to initialize twice"); 95 assert(_manager_array == NULL, "Attempt to initialize twice");
88 _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1 ); 96 _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1 );
89 guarantee(_manager_array != NULL, "Could not initialize promotion manager"); 97 guarantee(_manager_array != NULL, "Could not allocate manager_array");
90 98
91 _stack_array = new OopTaskQueueSet(parallel_gc_threads); 99 _stack_array = new OopTaskQueueSet(parallel_gc_threads);
92 guarantee(_stack_array != NULL, "Count not initialize promotion manager"); 100 guarantee(_stack_array != NULL, "Could not allocate stack_array");
101 _objarray_queues = new ObjArrayTaskQueueSet(parallel_gc_threads);
102 guarantee(_objarray_queues != NULL, "Could not allocate objarray_queues");
93 _region_array = new RegionTaskQueueSet(parallel_gc_threads); 103 _region_array = new RegionTaskQueueSet(parallel_gc_threads);
94 guarantee(_region_array != NULL, "Count not initialize promotion manager"); 104 guarantee(_region_array != NULL, "Could not allocate region_array");
95 105
96 // Create and register the ParCompactionManager(s) for the worker threads. 106 // Create and register the ParCompactionManager(s) for the worker threads.
97 for(uint i=0; i<parallel_gc_threads; i++) { 107 for(uint i=0; i<parallel_gc_threads; i++) {
98 _manager_array[i] = new ParCompactionManager(); 108 _manager_array[i] = new ParCompactionManager();
99 guarantee(_manager_array[i] != NULL, "Could not create ParCompactionManager"); 109 guarantee(_manager_array[i] != NULL, "Could not create ParCompactionManager");
100 stack_array()->register_queue(i, _manager_array[i]->marking_stack()); 110 stack_array()->register_queue(i, _manager_array[i]->marking_stack());
111 _objarray_queues->register_queue(i, &_manager_array[i]->_objarray_queue);
101 #ifdef USE_RegionTaskQueueWithOverflow 112 #ifdef USE_RegionTaskQueueWithOverflow
102 region_array()->register_queue(i, _manager_array[i]->region_stack()->task_queue()); 113 region_array()->register_queue(i, _manager_array[i]->region_stack()->task_queue());
103 #else 114 #else
104 region_array()->register_queue(i, _manager_array[i]->region_stack()); 115 region_array()->register_queue(i, _manager_array[i]->region_stack());
105 #endif 116 #endif
201 manager_array(i)->revisit_klass_stack()->clear(); 212 manager_array(i)->revisit_klass_stack()->clear();
202 manager_array(i)->revisit_mdo_stack()->clear(); 213 manager_array(i)->revisit_mdo_stack()->clear();
203 } 214 }
204 } 215 }
205 216
206 void ParCompactionManager::drain_marking_stacks(OopClosure* blk) { 217 void ParCompactionManager::follow_marking_stacks() {
207 #ifdef ASSERT
208 ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
209 assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
210 MutableSpace* to_space = heap->young_gen()->to_space();
211 MutableSpace* old_space = heap->old_gen()->object_space();
212 MutableSpace* perm_space = heap->perm_gen()->object_space();
213 #endif /* ASSERT */
214
215
216 do { 218 do {
217 219 // Drain the overflow stack first, to allow stealing from the marking stack.
218 // Drain overflow stack first, so other threads can steal from 220 while (!overflow_stack()->is_empty()) {
219 // claimed stack while we work. 221 overflow_stack()->pop()->follow_contents(this);
220 while(!overflow_stack()->is_empty()) { 222 }
221 oop obj = overflow_stack()->pop(); 223 oop obj;
224 while (marking_stack()->pop_local(obj)) {
222 obj->follow_contents(this); 225 obj->follow_contents(this);
223 } 226 }
224 227
225 oop obj; 228 ObjArrayTask task;
226 // obj is a reference!!! 229 while (!_objarray_overflow_stack->is_empty()) {
227 while (marking_stack()->pop_local(obj)) { 230 task = _objarray_overflow_stack->pop();
228 // It would be nice to assert about the type of objects we might 231 objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint();
229 // pop, but they can come from anywhere, unfortunately. 232 k->oop_follow_contents(this, task.obj(), task.index());
230 obj->follow_contents(this); 233 }
231 } 234 while (_objarray_queue.pop_local(task)) {
232 } while((marking_stack()->size() != 0) || (overflow_stack()->length() != 0)); 235 objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint();
233 236 k->oop_follow_contents(this, task.obj(), task.index());
234 assert(marking_stack()->size() == 0, "Sanity"); 237 }
235 assert(overflow_stack()->length() == 0, "Sanity"); 238 } while (!marking_stacks_empty());
239
240 assert(marking_stacks_empty(), "Sanity");
236 } 241 }
237 242
238 void ParCompactionManager::drain_region_overflow_stack() { 243 void ParCompactionManager::drain_region_overflow_stack() {
239 size_t region_index = (size_t) -1; 244 size_t region_index = (size_t) -1;
240 while(region_stack()->retrieve_from_overflow(region_index)) { 245 while(region_stack()->retrieve_from_overflow(region_index)) {