< prev index next >

src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp

Print this page




2752 
2753 CMSPhaseAccounting::~CMSPhaseAccounting() {
2754   _collector->gc_timer_cm()->register_gc_concurrent_end();
2755   _collector->stopTimer();
2756   log_debug(gc)("Concurrent active time: %.3fms", TimeHelper::counter_to_seconds(_collector->timerTicks()));
2757   log_trace(gc)(" (CMS %s yielded %d times)", _title, _collector->yields());
2758 }
2759 
2760 // CMS work
2761 
2762 // The common parts of CMSParInitialMarkTask and CMSParRemarkTask.
2763 class CMSParMarkTask : public AbstractGangTask {
2764  protected:
2765   CMSCollector*     _collector;
2766   uint              _n_workers;
2767   CMSParMarkTask(const char* name, CMSCollector* collector, uint n_workers) :
2768       AbstractGangTask(name),
2769       _collector(collector),
2770       _n_workers(n_workers) {}
2771   // Work method in support of parallel rescan ... of young gen spaces
2772   void do_young_space_rescan(uint worker_id, OopsInGenClosure* cl,
2773                              ContiguousSpace* space,
2774                              HeapWord** chunk_array, size_t chunk_top);
2775   void work_on_young_gen_roots(uint worker_id, OopsInGenClosure* cl);
2776 };
2777 
2778 // Parallel initial mark task
2779 class CMSParInitialMarkTask: public CMSParMarkTask {
2780   StrongRootsScope* _strong_roots_scope;
2781  public:
2782   CMSParInitialMarkTask(CMSCollector* collector, StrongRootsScope* strong_roots_scope, uint n_workers) :
2783       CMSParMarkTask("Scan roots and young gen for initial mark in parallel", collector, n_workers),
2784       _strong_roots_scope(strong_roots_scope) {}
2785   void work(uint worker_id);
2786 };
2787 
2788 // Checkpoint the roots into this generation from outside
2789 // this generation. [Note this initial checkpoint need only
2790 // be approximate -- we'll do a catch up phase subsequently.]
2791 void CMSCollector::checkpointRootsInitial() {
2792   assert(_collectorState == InitialMarking, "Wrong collector state");
2793   check_correct_thread_executing();
2794   TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
2795 


4238   _collectorState = Sweeping;
4239   // Call isAllClear() under bitMapLock
4240   assert(_modUnionTable.isAllClear(),
4241       "Should be clear by end of the final marking");
4242   assert(_ct->klass_rem_set()->mod_union_is_clear(),
4243       "Should be clear by end of the final marking");
4244 }
4245 
4246 void CMSParInitialMarkTask::work(uint worker_id) {
4247   elapsedTimer _timer;
4248   ResourceMark rm;
4249   HandleMark   hm;
4250 
4251   // ---------- scan from roots --------------
4252   _timer.start();
4253   GenCollectedHeap* gch = GenCollectedHeap::heap();
4254   ParMarkRefsIntoClosure par_mri_cl(_collector->_span, &(_collector->_markBitMap));
4255 
4256   // ---------- young gen roots --------------
4257   {
4258     work_on_young_gen_roots(worker_id, &par_mri_cl);
4259     _timer.stop();
4260     log_trace(gc, task)("Finished young gen initial mark scan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4261   }
4262 
4263   // ---------- remaining roots --------------
4264   _timer.reset();
4265   _timer.start();
4266 
4267   CLDToOopClosure cld_closure(&par_mri_cl, true);
4268 
4269   gch->gen_process_roots(_strong_roots_scope,
4270                          GenCollectedHeap::OldGen,
4271                          false,     // yg was scanned above
4272                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
4273                          _collector->should_unload_classes(),
4274                          &par_mri_cl,
4275                          NULL,
4276                          &cld_closure);
4277   assert(_collector->should_unload_classes()
4278          || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),


4329   RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
4330   void do_klass(Klass* k) {
4331     // Check if we have modified any oops in the Klass during the concurrent marking.
4332     if (k->has_accumulated_modified_oops()) {
4333       k->clear_accumulated_modified_oops();
4334 
4335       // We could have transfered the current modified marks to the accumulated marks,
4336       // like we do with the Card Table to Mod Union Table. But it's not really necessary.
4337     } else if (k->has_modified_oops()) {
4338       // Don't clear anything, this info is needed by the next young collection.
4339     } else {
4340       // No modified oops in the Klass.
4341       return;
4342     }
4343 
4344     // The klass has modified fields, need to scan the klass.
4345     _cm_klass_closure.do_klass(k);
4346   }
4347 };
4348 
4349 void CMSParMarkTask::work_on_young_gen_roots(uint worker_id, OopsInGenClosure* cl) {
4350   ParNewGeneration* young_gen = _collector->_young_gen;
4351   ContiguousSpace* eden_space = young_gen->eden();
4352   ContiguousSpace* from_space = young_gen->from();
4353   ContiguousSpace* to_space   = young_gen->to();
4354 
4355   HeapWord** eca = _collector->_eden_chunk_array;
4356   size_t     ect = _collector->_eden_chunk_index;
4357   HeapWord** sca = _collector->_survivor_chunk_array;
4358   size_t     sct = _collector->_survivor_chunk_index;
4359 
4360   assert(ect <= _collector->_eden_chunk_capacity, "out of bounds");
4361   assert(sct <= _collector->_survivor_chunk_capacity, "out of bounds");
4362 
4363   do_young_space_rescan(worker_id, cl, to_space, NULL, 0);
4364   do_young_space_rescan(worker_id, cl, from_space, sca, sct);
4365   do_young_space_rescan(worker_id, cl, eden_space, eca, ect);
4366 }
4367 
4368 // work_queue(i) is passed to the closure
4369 // ParMarkRefsIntoAndScanClosure.  The "i" parameter
4370 // also is passed to do_dirty_card_rescan_tasks() and to
4371 // do_work_steal() to select the i-th task_queue.
4372 
4373 void CMSParRemarkTask::work(uint worker_id) {
4374   elapsedTimer _timer;
4375   ResourceMark rm;
4376   HandleMark   hm;
4377 
4378   // ---------- rescan from roots --------------
4379   _timer.start();
4380   GenCollectedHeap* gch = GenCollectedHeap::heap();
4381   ParMarkRefsIntoAndScanClosure par_mrias_cl(_collector,
4382     _collector->_span, _collector->ref_processor(),
4383     &(_collector->_markBitMap),
4384     work_queue(worker_id));
4385 
4386   // Rescan young gen roots first since these are likely
4387   // coarsely partitioned and may, on that account, constitute
4388   // the critical path; thus, it's best to start off that
4389   // work first.
4390   // ---------- young gen roots --------------
4391   {
4392     work_on_young_gen_roots(worker_id, &par_mrias_cl);
4393     _timer.stop();
4394     log_trace(gc, task)("Finished young gen rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4395   }
4396 
4397   // ---------- remaining roots --------------
4398   _timer.reset();
4399   _timer.start();
4400   gch->gen_process_roots(_strong_roots_scope,
4401                          GenCollectedHeap::OldGen,
4402                          false,     // yg was scanned above
4403                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
4404                          _collector->should_unload_classes(),
4405                          &par_mrias_cl,
4406                          NULL,
4407                          NULL);     // The dirty klasses will be handled below
4408 
4409   assert(_collector->should_unload_classes()
4410          || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
4411          "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
4412   _timer.stop();


4454   // ---------- rescan dirty cards ------------
4455   _timer.reset();
4456   _timer.start();
4457 
4458   // Do the rescan tasks for each of the two spaces
4459   // (cms_space) in turn.
4460   // "worker_id" is passed to select the task_queue for "worker_id"
4461   do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl);
4462   _timer.stop();
4463   log_trace(gc, task)("Finished dirty card rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4464 
4465   // ---------- steal work from other threads ...
4466   // ---------- ... and drain overflow list.
4467   _timer.reset();
4468   _timer.start();
4469   do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id));
4470   _timer.stop();
4471   log_trace(gc, task)("Finished work stealing in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4472 }
4473 
4474 // Note that parameter "i" is not used.
4475 void
4476 CMSParMarkTask::do_young_space_rescan(uint worker_id,
4477   OopsInGenClosure* cl, ContiguousSpace* space,
4478   HeapWord** chunk_array, size_t chunk_top) {
4479   // Until all tasks completed:
4480   // . claim an unclaimed task
4481   // . compute region boundaries corresponding to task claimed
4482   //   using chunk_array
4483   // . par_oop_iterate(cl) over that region
4484 
4485   ResourceMark rm;
4486   HandleMark   hm;
4487 
4488   SequentialSubTasksDone* pst = space->par_seq_tasks();
4489 
4490   uint nth_task = 0;
4491   uint n_tasks  = pst->n_tasks();
4492 
4493   if (n_tasks > 0) {
4494     assert(pst->valid(), "Uninitialized use?");
4495     HeapWord *start, *end;
4496     while (!pst->is_task_claimed(/* reference */ nth_task)) {




2752 
2753 CMSPhaseAccounting::~CMSPhaseAccounting() {
2754   _collector->gc_timer_cm()->register_gc_concurrent_end();
2755   _collector->stopTimer();
2756   log_debug(gc)("Concurrent active time: %.3fms", TimeHelper::counter_to_seconds(_collector->timerTicks()));
2757   log_trace(gc)(" (CMS %s yielded %d times)", _title, _collector->yields());
2758 }
2759 
2760 // CMS work
2761 
2762 // The common parts of CMSParInitialMarkTask and CMSParRemarkTask.
2763 class CMSParMarkTask : public AbstractGangTask {
2764  protected:
2765   CMSCollector*     _collector;
2766   uint              _n_workers;
2767   CMSParMarkTask(const char* name, CMSCollector* collector, uint n_workers) :
2768       AbstractGangTask(name),
2769       _collector(collector),
2770       _n_workers(n_workers) {}
2771   // Work method in support of parallel rescan ... of young gen spaces
2772   void do_young_space_rescan(OopsInGenClosure* cl,
2773                              ContiguousSpace* space,
2774                              HeapWord** chunk_array, size_t chunk_top);
2775   void work_on_young_gen_roots(OopsInGenClosure* cl);
2776 };
2777 
2778 // Parallel initial mark task
2779 class CMSParInitialMarkTask: public CMSParMarkTask {
2780   StrongRootsScope* _strong_roots_scope;
2781  public:
2782   CMSParInitialMarkTask(CMSCollector* collector, StrongRootsScope* strong_roots_scope, uint n_workers) :
2783       CMSParMarkTask("Scan roots and young gen for initial mark in parallel", collector, n_workers),
2784       _strong_roots_scope(strong_roots_scope) {}
2785   void work(uint worker_id);
2786 };
2787 
2788 // Checkpoint the roots into this generation from outside
2789 // this generation. [Note this initial checkpoint need only
2790 // be approximate -- we'll do a catch up phase subsequently.]
2791 void CMSCollector::checkpointRootsInitial() {
2792   assert(_collectorState == InitialMarking, "Wrong collector state");
2793   check_correct_thread_executing();
2794   TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
2795 


4238   _collectorState = Sweeping;
4239   // Call isAllClear() under bitMapLock
4240   assert(_modUnionTable.isAllClear(),
4241       "Should be clear by end of the final marking");
4242   assert(_ct->klass_rem_set()->mod_union_is_clear(),
4243       "Should be clear by end of the final marking");
4244 }
4245 
4246 void CMSParInitialMarkTask::work(uint worker_id) {
4247   elapsedTimer _timer;
4248   ResourceMark rm;
4249   HandleMark   hm;
4250 
4251   // ---------- scan from roots --------------
4252   _timer.start();
4253   GenCollectedHeap* gch = GenCollectedHeap::heap();
4254   ParMarkRefsIntoClosure par_mri_cl(_collector->_span, &(_collector->_markBitMap));
4255 
4256   // ---------- young gen roots --------------
4257   {
4258     work_on_young_gen_roots(&par_mri_cl);
4259     _timer.stop();
4260     log_trace(gc, task)("Finished young gen initial mark scan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4261   }
4262 
4263   // ---------- remaining roots --------------
4264   _timer.reset();
4265   _timer.start();
4266 
4267   CLDToOopClosure cld_closure(&par_mri_cl, true);
4268 
4269   gch->gen_process_roots(_strong_roots_scope,
4270                          GenCollectedHeap::OldGen,
4271                          false,     // yg was scanned above
4272                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
4273                          _collector->should_unload_classes(),
4274                          &par_mri_cl,
4275                          NULL,
4276                          &cld_closure);
4277   assert(_collector->should_unload_classes()
4278          || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),


4329   RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
4330   void do_klass(Klass* k) {
4331     // Check if we have modified any oops in the Klass during the concurrent marking.
4332     if (k->has_accumulated_modified_oops()) {
4333       k->clear_accumulated_modified_oops();
4334 
4335       // We could have transfered the current modified marks to the accumulated marks,
4336       // like we do with the Card Table to Mod Union Table. But it's not really necessary.
4337     } else if (k->has_modified_oops()) {
4338       // Don't clear anything, this info is needed by the next young collection.
4339     } else {
4340       // No modified oops in the Klass.
4341       return;
4342     }
4343 
4344     // The klass has modified fields, need to scan the klass.
4345     _cm_klass_closure.do_klass(k);
4346   }
4347 };
4348 
4349 void CMSParMarkTask::work_on_young_gen_roots(OopsInGenClosure* cl) {
4350   ParNewGeneration* young_gen = _collector->_young_gen;
4351   ContiguousSpace* eden_space = young_gen->eden();
4352   ContiguousSpace* from_space = young_gen->from();
4353   ContiguousSpace* to_space   = young_gen->to();
4354 
4355   HeapWord** eca = _collector->_eden_chunk_array;
4356   size_t     ect = _collector->_eden_chunk_index;
4357   HeapWord** sca = _collector->_survivor_chunk_array;
4358   size_t     sct = _collector->_survivor_chunk_index;
4359 
4360   assert(ect <= _collector->_eden_chunk_capacity, "out of bounds");
4361   assert(sct <= _collector->_survivor_chunk_capacity, "out of bounds");
4362 
4363   do_young_space_rescan(cl, to_space, NULL, 0);
4364   do_young_space_rescan(cl, from_space, sca, sct);
4365   do_young_space_rescan(cl, eden_space, eca, ect);
4366 }
4367 
4368 // work_queue(i) is passed to the closure
4369 // ParMarkRefsIntoAndScanClosure.  The "i" parameter
4370 // also is passed to do_dirty_card_rescan_tasks() and to
4371 // do_work_steal() to select the i-th task_queue.
4372 
4373 void CMSParRemarkTask::work(uint worker_id) {
4374   elapsedTimer _timer;
4375   ResourceMark rm;
4376   HandleMark   hm;
4377 
4378   // ---------- rescan from roots --------------
4379   _timer.start();
4380   GenCollectedHeap* gch = GenCollectedHeap::heap();
4381   ParMarkRefsIntoAndScanClosure par_mrias_cl(_collector,
4382     _collector->_span, _collector->ref_processor(),
4383     &(_collector->_markBitMap),
4384     work_queue(worker_id));
4385 
4386   // Rescan young gen roots first since these are likely
4387   // coarsely partitioned and may, on that account, constitute
4388   // the critical path; thus, it's best to start off that
4389   // work first.
4390   // ---------- young gen roots --------------
4391   {
4392     work_on_young_gen_roots(&par_mrias_cl);
4393     _timer.stop();
4394     log_trace(gc, task)("Finished young gen rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4395   }
4396 
4397   // ---------- remaining roots --------------
4398   _timer.reset();
4399   _timer.start();
4400   gch->gen_process_roots(_strong_roots_scope,
4401                          GenCollectedHeap::OldGen,
4402                          false,     // yg was scanned above
4403                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
4404                          _collector->should_unload_classes(),
4405                          &par_mrias_cl,
4406                          NULL,
4407                          NULL);     // The dirty klasses will be handled below
4408 
4409   assert(_collector->should_unload_classes()
4410          || (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
4411          "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops");
4412   _timer.stop();


4454   // ---------- rescan dirty cards ------------
4455   _timer.reset();
4456   _timer.start();
4457 
4458   // Do the rescan tasks for each of the two spaces
4459   // (cms_space) in turn.
4460   // "worker_id" is passed to select the task_queue for "worker_id"
4461   do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl);
4462   _timer.stop();
4463   log_trace(gc, task)("Finished dirty card rescan work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4464 
4465   // ---------- steal work from other threads ...
4466   // ---------- ... and drain overflow list.
4467   _timer.reset();
4468   _timer.start();
4469   do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id));
4470   _timer.stop();
4471   log_trace(gc, task)("Finished work stealing in %dth thread: %3.3f sec", worker_id, _timer.seconds());
4472 }
4473 

4474 void
4475 CMSParMarkTask::do_young_space_rescan(
4476   OopsInGenClosure* cl, ContiguousSpace* space,
4477   HeapWord** chunk_array, size_t chunk_top) {
4478   // Until all tasks completed:
4479   // . claim an unclaimed task
4480   // . compute region boundaries corresponding to task claimed
4481   //   using chunk_array
4482   // . par_oop_iterate(cl) over that region
4483 
4484   ResourceMark rm;
4485   HandleMark   hm;
4486 
4487   SequentialSubTasksDone* pst = space->par_seq_tasks();
4488 
4489   uint nth_task = 0;
4490   uint n_tasks  = pst->n_tasks();
4491 
4492   if (n_tasks > 0) {
4493     assert(pst->valid(), "Uninitialized use?");
4494     HeapWord *start, *end;
4495     while (!pst->is_task_claimed(/* reference */ nth_task)) {


< prev index next >