OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 int Heap::gc_count_ = 0; | 119 int Heap::gc_count_ = 0; |
120 | 120 |
121 GCTracer* Heap::tracer_ = NULL; | 121 GCTracer* Heap::tracer_ = NULL; |
122 | 122 |
123 int Heap::unflattened_strings_length_ = 0; | 123 int Heap::unflattened_strings_length_ = 0; |
124 | 124 |
125 int Heap::always_allocate_scope_depth_ = 0; | 125 int Heap::always_allocate_scope_depth_ = 0; |
126 int Heap::linear_allocation_scope_depth_ = 0; | 126 int Heap::linear_allocation_scope_depth_ = 0; |
127 int Heap::contexts_disposed_ = 0; | 127 int Heap::contexts_disposed_ = 0; |
128 | 128 |
| 129 int Heap::young_survivors_after_last_gc_ = 0; |
| 130 int Heap::high_survival_rate_period_length_ = 0; |
| 131 int Heap::survival_rate_ = 0; |
| 132 Heap::SurvivalRateTrend Heap::previous_survival_rate_trend_ = Heap::STABLE; |
| 133 Heap::SurvivalRateTrend Heap::survival_rate_trend_ = Heap::STABLE; |
| 134 bool Heap::bumped_old_gen_limits_ = false; |
| 135 |
129 #ifdef DEBUG | 136 #ifdef DEBUG |
130 bool Heap::allocation_allowed_ = true; | 137 bool Heap::allocation_allowed_ = true; |
131 | 138 |
132 int Heap::allocation_timeout_ = 0; | 139 int Heap::allocation_timeout_ = 0; |
133 bool Heap::disallow_allocation_failure_ = false; | 140 bool Heap::disallow_allocation_failure_ = false; |
134 #endif // DEBUG | 141 #endif // DEBUG |
135 | 142 |
136 int GCTracer::alive_after_last_gc_ = 0; | 143 int GCTracer::alive_after_last_gc_ = 0; |
137 double GCTracer::last_gc_end_timestamp_ = 0.0; | 144 double GCTracer::last_gc_end_timestamp_ = 0.0; |
138 int GCTracer::max_gc_pause_ = 0; | 145 int GCTracer::max_gc_pause_ = 0; |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 PageWatermarkValidity validity) { | 582 PageWatermarkValidity validity) { |
576 PageIterator it(space, PageIterator::PAGES_IN_USE); | 583 PageIterator it(space, PageIterator::PAGES_IN_USE); |
577 bool expected_value = (validity == ALL_VALID); | 584 bool expected_value = (validity == ALL_VALID); |
578 while (it.has_next()) { | 585 while (it.has_next()) { |
579 Page* page = it.next(); | 586 Page* page = it.next(); |
580 ASSERT(page->IsWatermarkValid() == expected_value); | 587 ASSERT(page->IsWatermarkValid() == expected_value); |
581 } | 588 } |
582 } | 589 } |
583 #endif | 590 #endif |
584 | 591 |
| 592 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { |
| 593 double survival_rate = |
| 594 (static_cast<double>(young_survivors_after_last_gc_) * 100) / |
| 595 start_new_space_size; |
| 596 |
| 597 if (survival_rate > kYoungSurvivalRateThreshold) { |
| 598 high_survival_rate_period_length_++; |
| 599 } else { |
| 600 high_survival_rate_period_length_ = 0; |
| 601 } |
| 602 |
| 603 double survival_rate_diff = survival_rate_ - survival_rate; |
| 604 |
| 605 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) { |
| 606 set_survival_rate_trend(DECREASING); |
| 607 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) { |
| 608 set_survival_rate_trend(INCREASING); |
| 609 } else { |
| 610 set_survival_rate_trend(STABLE); |
| 611 } |
| 612 |
| 613 survival_rate_ = survival_rate; |
| 614 } |
585 | 615 |
586 void Heap::PerformGarbageCollection(AllocationSpace space, | 616 void Heap::PerformGarbageCollection(AllocationSpace space, |
587 GarbageCollector collector, | 617 GarbageCollector collector, |
588 GCTracer* tracer) { | 618 GCTracer* tracer) { |
589 VerifySymbolTable(); | 619 VerifySymbolTable(); |
590 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { | 620 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { |
591 ASSERT(!allocation_allowed_); | 621 ASSERT(!allocation_allowed_); |
592 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 622 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
593 global_gc_prologue_callback_(); | 623 global_gc_prologue_callback_(); |
594 } | 624 } |
595 | 625 |
596 GCType gc_type = | 626 GCType gc_type = |
597 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; | 627 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; |
598 | 628 |
599 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 629 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { |
600 if (gc_type & gc_prologue_callbacks_[i].gc_type) { | 630 if (gc_type & gc_prologue_callbacks_[i].gc_type) { |
601 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); | 631 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags); |
602 } | 632 } |
603 } | 633 } |
604 | 634 |
605 EnsureFromSpaceIsCommitted(); | 635 EnsureFromSpaceIsCommitted(); |
606 | 636 |
| 637 int start_new_space_size = Heap::new_space()->Size(); |
| 638 |
607 if (collector == MARK_COMPACTOR) { | 639 if (collector == MARK_COMPACTOR) { |
608 if (FLAG_flush_code) { | 640 if (FLAG_flush_code) { |
609 // Flush all potentially unused code. | 641 // Flush all potentially unused code. |
610 FlushCode(); | 642 FlushCode(); |
611 } | 643 } |
612 | 644 |
613 // Perform mark-sweep with optional compaction. | 645 // Perform mark-sweep with optional compaction. |
614 MarkCompact(tracer); | 646 MarkCompact(tracer); |
615 | 647 |
| 648 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() && |
| 649 IsStableOrIncreasingSurvivalTrend(); |
| 650 |
| 651 UpdateSurvivalRateTrend(start_new_space_size); |
| 652 |
616 int old_gen_size = PromotedSpaceSize(); | 653 int old_gen_size = PromotedSpaceSize(); |
617 old_gen_promotion_limit_ = | 654 old_gen_promotion_limit_ = |
618 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); | 655 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); |
619 old_gen_allocation_limit_ = | 656 old_gen_allocation_limit_ = |
620 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2); | 657 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2); |
| 658 |
| 659 if (high_survival_rate_during_scavenges && |
| 660 IsStableOrIncreasingSurvivalTrend()) { |
| 661 // Stable high survival rates of young objects both during partial and |
| 662 // full collection indicate that mutator is either building or modifying |
| 663 // a structure with a long lifetime. |
| 664 // In this case we aggressively raise old generation memory limits to |
| 665 // postpone subsequent mark-sweep collection and thus trade memory |
| 666 // space for the mutation speed. |
| 667 old_gen_promotion_limit_ *= 2; |
| 668 old_gen_allocation_limit_ *= 2; |
| 669 bumped_old_gen_limits_ = true; |
| 670 } |
| 671 |
621 old_gen_exhausted_ = false; | 672 old_gen_exhausted_ = false; |
622 } else { | 673 } else { |
623 tracer_ = tracer; | 674 tracer_ = tracer; |
624 Scavenge(); | 675 Scavenge(); |
625 tracer_ = NULL; | 676 tracer_ = NULL; |
| 677 |
| 678 UpdateSurvivalRateTrend(start_new_space_size); |
| 679 |
| 680 if (bumped_old_gen_limits_ && |
| 681 !IsHighSurvivalRate() && |
| 682 !IsIncreasingSurvivalTrend()) { |
| 683 // We previously observed high survival rates in young space and decided |
| 684 // to bump old space allocation limits to trade the space for the speed |
| 685 // but now survival rates are dropping which indicates that mutator |
| 686 // finished updating tenured data structure. So we can decrease old space |
| 687 // limits to guarantee an early full GC cycle and reduce memory footprint. |
| 688 old_gen_promotion_limit_ /= 2; |
| 689 old_gen_allocation_limit_ /= 2; |
| 690 bumped_old_gen_limits_ = false; |
| 691 } |
626 } | 692 } |
627 | 693 |
628 Counters::objs_since_last_young.Set(0); | 694 Counters::objs_since_last_young.Set(0); |
629 | 695 |
630 if (collector == MARK_COMPACTOR) { | 696 if (collector == MARK_COMPACTOR) { |
631 DisableAssertNoAllocation allow_allocation; | 697 DisableAssertNoAllocation allow_allocation; |
632 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 698 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
633 GlobalHandles::PostGarbageCollectionProcessing(); | 699 GlobalHandles::PostGarbageCollectionProcessing(); |
634 } | 700 } |
635 | 701 |
(...skipping 4133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4769 void ExternalStringTable::TearDown() { | 4835 void ExternalStringTable::TearDown() { |
4770 new_space_strings_.Free(); | 4836 new_space_strings_.Free(); |
4771 old_space_strings_.Free(); | 4837 old_space_strings_.Free(); |
4772 } | 4838 } |
4773 | 4839 |
4774 | 4840 |
4775 List<Object*> ExternalStringTable::new_space_strings_; | 4841 List<Object*> ExternalStringTable::new_space_strings_; |
4776 List<Object*> ExternalStringTable::old_space_strings_; | 4842 List<Object*> ExternalStringTable::old_space_strings_; |
4777 | 4843 |
4778 } } // namespace v8::internal | 4844 } } // namespace v8::internal |
OLD | NEW |