OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 4803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4814 | 4814 |
4815 void Heap::EnsureHeapIsIterable() { | 4815 void Heap::EnsureHeapIsIterable() { |
4816 ASSERT(IsAllocationAllowed()); | 4816 ASSERT(IsAllocationAllowed()); |
4817 if (!IsHeapIterable()) { | 4817 if (!IsHeapIterable()) { |
4818 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); | 4818 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); |
4819 } | 4819 } |
4820 ASSERT(IsHeapIterable()); | 4820 ASSERT(IsHeapIterable()); |
4821 } | 4821 } |
4822 | 4822 |
4823 | 4823 |
4824 void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) { | |
ulan
2012/03/16 13:37:23
This function is extracted from lines 4876-4894 of
| |
4825 // This flag prevents incremental marking from requesting GC via stack guard | |
4826 idle_notification_will_schedule_next_gc_ = true; | |
4827 incremental_marking()->Step(step_size); | |
4828 idle_notification_will_schedule_next_gc_ = false; | |
4829 | |
4830 if (incremental_marking()->IsComplete()) { | |
4831 bool uncommit = false; | |
4832 if (gc_count_at_last_idle_gc_ == gc_count_) { | |
4833 // No GC since the last full GC, the mutator is probably not active. | |
4834 isolate_->compilation_cache()->Clear(); | |
4835 uncommit = true; | |
4836 } | |
4837 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); | |
4838 gc_count_at_last_idle_gc_ = gc_count_; | |
4839 if (uncommit) { | |
4840 new_space_.Shrink(); | |
4841 UncommitFromSpace(); | |
4842 } | |
4843 } | |
4844 } | |
4845 | |
4846 | |
4824 bool Heap::IdleNotification(int hint) { | 4847 bool Heap::IdleNotification(int hint) { |
4825 if (hint >= 1000) return IdleGlobalGC(); | 4848 intptr_t size_factor = Min(Max(hint, 30), 1000) / 10; |
4826 if (contexts_disposed_ > 0 || !FLAG_incremental_marking || | 4849 // The size factor is in range [3..100]. |
4850 intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold; | |
4851 | |
4852 if (contexts_disposed_ > 0) { | |
4853 if (hint > TimeMarkSweepWouldTakeInMs() && !FLAG_expose_gc) { | |
4854 HistogramTimerScope scope(isolate_->counters()->gc_context()); | |
4855 CollectAllGarbage(kReduceMemoryFootprintMask, | |
4856 "idle notification: contexts disposed"); | |
4857 } else { | |
4858 AdvanceIdleIncrementalMarking(step_size); | |
4859 contexts_disposed_ = 0; | |
4860 } | |
4861 // Make sure that we have no pending context disposals. | |
4862 // Take into account that we might have decided to delay full collection | |
4863 // because incremental marking is in progress. | |
4864 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped()); | |
4865 return false; | |
4866 } | |
4867 | |
4868 if (hint >= 1000 || !FLAG_incremental_marking || | |
ulan
2012/03/16 13:37:23
Once this CL lands into Chromium without memory re
| |
4827 FLAG_expose_gc || Serializer::enabled()) { | 4869 FLAG_expose_gc || Serializer::enabled()) { |
4828 return true; | 4870 return IdleGlobalGC(); |
4829 } | 4871 } |
4830 | 4872 |
4831 // By doing small chunks of GC work in each IdleNotification, | 4873 // By doing small chunks of GC work in each IdleNotification, |
4832 // perform a round of incremental GCs and after that wait until | 4874 // perform a round of incremental GCs and after that wait until |
4833 // the mutator creates enough garbage to justify a new round. | 4875 // the mutator creates enough garbage to justify a new round. |
4834 // An incremental GC progresses as follows: | 4876 // An incremental GC progresses as follows: |
4835 // 1. many incremental marking steps, | 4877 // 1. many incremental marking steps, |
4836 // 2. one old space mark-sweep-compact, | 4878 // 2. one old space mark-sweep-compact, |
4837 // 3. many lazy sweep steps. | 4879 // 3. many lazy sweep steps. |
4838 // Use mark-sweep-compact events to count incremental GCs in a round. | 4880 // Use mark-sweep-compact events to count incremental GCs in a round. |
4839 | 4881 |
4840 intptr_t size_factor = Min(Max(hint, 30), 1000) / 10; | |
4841 // The size factor is in range [3..100]. | |
4842 intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold; | |
4843 | 4882 |
4844 if (incremental_marking()->IsStopped()) { | 4883 if (incremental_marking()->IsStopped()) { |
4845 if (!IsSweepingComplete() && | 4884 if (!IsSweepingComplete() && |
4846 !AdvanceSweepers(static_cast<int>(step_size))) { | 4885 !AdvanceSweepers(static_cast<int>(step_size))) { |
4847 return false; | 4886 return false; |
4848 } | 4887 } |
4849 } | 4888 } |
4850 | 4889 |
4851 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { | 4890 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { |
4852 if (EnoughGarbageSinceLastIdleRound()) { | 4891 if (EnoughGarbageSinceLastIdleRound()) { |
4853 StartIdleRound(); | 4892 StartIdleRound(); |
4854 } else { | 4893 } else { |
4855 return true; | 4894 return true; |
4856 } | 4895 } |
4857 } | 4896 } |
4858 | 4897 |
4859 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_; | 4898 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_; |
4860 mark_sweeps_since_idle_round_started_ += new_mark_sweeps; | 4899 mark_sweeps_since_idle_round_started_ += new_mark_sweeps; |
4861 ms_count_at_last_idle_notification_ = ms_count_; | 4900 ms_count_at_last_idle_notification_ = ms_count_; |
4862 | 4901 |
4863 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { | 4902 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { |
4864 FinishIdleRound(); | 4903 FinishIdleRound(); |
4865 return true; | 4904 return true; |
4866 } | 4905 } |
4867 | 4906 |
4868 if (incremental_marking()->IsStopped()) { | 4907 if (incremental_marking()->IsStopped()) { |
4869 if (hint < 1000 && !WorthStartingGCWhenIdle()) { | 4908 if (!WorthStartingGCWhenIdle()) { |
4870 FinishIdleRound(); | 4909 FinishIdleRound(); |
4871 return true; | 4910 return true; |
4872 } | 4911 } |
4873 incremental_marking()->Start(); | 4912 incremental_marking()->Start(); |
4874 } | 4913 } |
4875 | 4914 |
4876 // This flag prevents incremental marking from requesting GC via stack guard | 4915 AdvanceIdleIncrementalMarking(step_size); |
4877 idle_notification_will_schedule_next_gc_ = true; | |
4878 incremental_marking()->Step(step_size); | |
4879 idle_notification_will_schedule_next_gc_ = false; | |
4880 | |
4881 if (incremental_marking()->IsComplete()) { | |
4882 bool uncommit = false; | |
4883 if (gc_count_at_last_idle_gc_ == gc_count_) { | |
4884 // No GC since the last full GC, the mutator is probably not active. | |
4885 isolate_->compilation_cache()->Clear(); | |
4886 uncommit = true; | |
4887 } | |
4888 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); | |
4889 gc_count_at_last_idle_gc_ = gc_count_; | |
4890 if (uncommit) { | |
4891 new_space_.Shrink(); | |
4892 UncommitFromSpace(); | |
4893 } | |
4894 } | |
4895 return false; | 4916 return false; |
4896 } | 4917 } |
4897 | 4918 |
4898 | 4919 |
4899 bool Heap::IdleGlobalGC() { | 4920 bool Heap::IdleGlobalGC() { |
4900 static const int kIdlesBeforeScavenge = 4; | 4921 static const int kIdlesBeforeScavenge = 4; |
4901 static const int kIdlesBeforeMarkSweep = 7; | 4922 static const int kIdlesBeforeMarkSweep = 7; |
4902 static const int kIdlesBeforeMarkCompact = 8; | 4923 static const int kIdlesBeforeMarkCompact = 8; |
4903 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; | 4924 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
4904 static const unsigned int kGCsBetweenCleanup = 4; | 4925 static const unsigned int kGCsBetweenCleanup = 4; |
(...skipping 12 matching lines...) Expand all Loading... | |
4917 // provoke a number of garbage collections. | 4938 // provoke a number of garbage collections. |
4918 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) { | 4939 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) { |
4919 number_idle_notifications_ = | 4940 number_idle_notifications_ = |
4920 Min(number_idle_notifications_ + 1, kMaxIdleCount); | 4941 Min(number_idle_notifications_ + 1, kMaxIdleCount); |
4921 } else { | 4942 } else { |
4922 number_idle_notifications_ = 0; | 4943 number_idle_notifications_ = 0; |
4923 last_idle_notification_gc_count_ = gc_count_; | 4944 last_idle_notification_gc_count_ = gc_count_; |
4924 } | 4945 } |
4925 | 4946 |
4926 if (number_idle_notifications_ == kIdlesBeforeScavenge) { | 4947 if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
4927 if (contexts_disposed_ > 0) { | 4948 CollectGarbage(NEW_SPACE, "idle notification"); |
4928 HistogramTimerScope scope(isolate_->counters()->gc_context()); | |
4929 CollectAllGarbage(kReduceMemoryFootprintMask, | |
4930 "idle notification: contexts disposed"); | |
4931 } else { | |
4932 CollectGarbage(NEW_SPACE, "idle notification"); | |
4933 } | |
4934 new_space_.Shrink(); | 4949 new_space_.Shrink(); |
4935 last_idle_notification_gc_count_ = gc_count_; | 4950 last_idle_notification_gc_count_ = gc_count_; |
4936 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { | 4951 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { |
4937 // Before doing the mark-sweep collections we clear the | 4952 // Before doing the mark-sweep collections we clear the |
4938 // compilation cache to avoid hanging on to source code and | 4953 // compilation cache to avoid hanging on to source code and |
4939 // generated code for cached functions. | 4954 // generated code for cached functions. |
4940 isolate_->compilation_cache()->Clear(); | 4955 isolate_->compilation_cache()->Clear(); |
4941 | 4956 |
4942 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); | 4957 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
4943 new_space_.Shrink(); | 4958 new_space_.Shrink(); |
4944 last_idle_notification_gc_count_ = gc_count_; | 4959 last_idle_notification_gc_count_ = gc_count_; |
4945 | 4960 |
4946 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { | 4961 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
4947 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); | 4962 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
4948 new_space_.Shrink(); | 4963 new_space_.Shrink(); |
4949 last_idle_notification_gc_count_ = gc_count_; | 4964 last_idle_notification_gc_count_ = gc_count_; |
4950 number_idle_notifications_ = 0; | 4965 number_idle_notifications_ = 0; |
4951 finished = true; | 4966 finished = true; |
4952 } else if (contexts_disposed_ > 0) { | |
4953 if (FLAG_expose_gc) { | |
4954 contexts_disposed_ = 0; | |
4955 } else { | |
4956 HistogramTimerScope scope(isolate_->counters()->gc_context()); | |
4957 CollectAllGarbage(kReduceMemoryFootprintMask, | |
4958 "idle notification: contexts disposed"); | |
4959 last_idle_notification_gc_count_ = gc_count_; | |
4960 } | |
4961 // If this is the first idle notification, we reset the | |
4962 // notification count to avoid letting idle notifications for | |
4963 // context disposal garbage collections start a potentially too | |
4964 // aggressive idle GC cycle. | |
4965 if (number_idle_notifications_ <= 1) { | |
4966 number_idle_notifications_ = 0; | |
4967 uncommit = false; | |
4968 } | |
4969 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { | 4967 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { |
4970 // If we have received more than kIdlesBeforeMarkCompact idle | 4968 // If we have received more than kIdlesBeforeMarkCompact idle |
4971 // notifications we do not perform any cleanup because we don't | 4969 // notifications we do not perform any cleanup because we don't |
4972 // expect to gain much by doing so. | 4970 // expect to gain much by doing so. |
4973 finished = true; | 4971 finished = true; |
4974 } | 4972 } |
4975 | 4973 |
4976 // Make sure that we have no pending context disposals and | |
4977 // conditionally uncommit from space. | |
4978 // Take into account that we might have decided to delay full collection | |
4979 // because incremental marking is in progress. | |
4980 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped()); | |
4981 if (uncommit) UncommitFromSpace(); | 4974 if (uncommit) UncommitFromSpace(); |
4982 | 4975 |
4983 return finished; | 4976 return finished; |
4984 } | 4977 } |
4985 | 4978 |
4986 | 4979 |
4987 #ifdef DEBUG | 4980 #ifdef DEBUG |
4988 | 4981 |
4989 void Heap::Print() { | 4982 void Heap::Print() { |
4990 if (!HasBeenSetUp()) return; | 4983 if (!HasBeenSetUp()) return; |
(...skipping 1974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6965 isolate_->heap()->store_buffer()->Compact(); | 6958 isolate_->heap()->store_buffer()->Compact(); |
6966 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); | 6959 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
6967 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 6960 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
6968 next = chunk->next_chunk(); | 6961 next = chunk->next_chunk(); |
6969 isolate_->memory_allocator()->Free(chunk); | 6962 isolate_->memory_allocator()->Free(chunk); |
6970 } | 6963 } |
6971 chunks_queued_for_free_ = NULL; | 6964 chunks_queued_for_free_ = NULL; |
6972 } | 6965 } |
6973 | 6966 |
6974 } } // namespace v8::internal | 6967 } } // namespace v8::internal |
OLD | NEW |