Chromium Code Reviews| Index: src/heap.cc |
| diff --git a/src/heap.cc b/src/heap.cc |
| index 4da83e859e3ddff3f2988c00f066ab63ddf58c04..8e4c833a26cf3610bdee79e272ef54ad8ac2443f 100644 |
| --- a/src/heap.cc |
| +++ b/src/heap.cc |
| @@ -143,6 +143,7 @@ Heap::Heap() |
| number_idle_notifications_(0), |
| last_idle_notification_gc_count_(0), |
| last_idle_notification_gc_count_init_(false), |
| + idle_notification_will_schedule_next_gc_(false), |
| configured_(false), |
| chunks_queued_for_free_(NULL) { |
| // Allow build-time customization of the max semispace size. Building |
| @@ -513,7 +514,8 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
| } |
| ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); |
| - if (incremental_marking()->IsStopped()) { |
| + if (incremental_marking()->IsStopped() && |
| + !idle_notification_will_schedule_next_gc()) { |
|
Erik Corry
2011/11/10 15:06:55
I think if the heuristics say we need to start a G
ulan
2011/11/11 13:27:26
Removed the flag.
|
| if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { |
| incremental_marking()->Start(); |
| } |
| @@ -4461,17 +4463,88 @@ void Heap::EnsureHeapIsIterable() { |
| bool Heap::IdleNotification() { |
|
Erik Corry
2011/11/10 15:06:55
A comment here to say what the return value means
ulan
2011/11/11 13:27:26
This function is documented in V8 API. Added a com
|
| - static const int kIdlesBeforeScavenge = 4; |
| - static const int kIdlesBeforeMarkSweep = 7; |
| - static const int kIdlesBeforeMarkCompact = 8; |
| - static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; |
| - static const unsigned int kGCsBetweenCleanup = 4; |
| - |
| if (!last_idle_notification_gc_count_init_) { |
| last_idle_notification_gc_count_ = gc_count_; |
| last_idle_notification_gc_count_init_ = true; |
| + last_idle_notification_timestamp_ = OS::TimeCurrentMillis(); |
| + } |
| + |
| + if (!FLAG_incremental_marking) return IdleGlobalGC(); |
| + |
| + // The goal is to perform kMaxIdleCount incremental GC cycles and then |
| + // wait until the mutator creates more garbage. |
|
Erik Corry
2011/11/10 15:06:55
"Creates more garbage" is rather vague. If this m
ulan
2011/11/11 13:27:26
Rephrased it to "enough garbage to justify a new r
|
| + // A GC cycle consists of: |
| + // 1. many incremental marking steps, |
| + // 2. one old space mark-sweep-compact, |
| + // 3. many lazy sweep steps. |
| + // The counters from IdleGlobalGC are reused, but have different meaning: |
|
Erik Corry
2011/11/10 15:06:55
This seems unnecessarily complicated. Counters ar
ulan
2011/11/11 13:27:26
Done.
|
| + // - number_idle_notifications_ counts the GC cycles. |
|
Erik Corry
2011/11/10 15:06:55
I do not like the phrase "GC cycles". If we use t
ulan
2011/11/11 13:27:26
Done.
|
| + // - last_idle_notification_gc_count_ stores the gc_count_ after the last |
| + // old space mark-sweep-compact. |
| + |
| + if (number_idle_notifications_ >= kMaxIdleCount && |
| + gc_count_ - last_idle_notification_gc_count_ >= kGCsBetweenCleanup) { |
| + // The mutator created more garbage, start new round of GC cycles. |
| + number_idle_notifications_ = 0; |
| } |
| + intptr_t step_size = IncrementalMarking::kStepFakeAllocatedBytes; |
| + |
| + double delay = OS::TimeCurrentMillis() - last_idle_notification_timestamp_; |
| + last_idle_notification_timestamp_ += delay; |
| + |
| + if (delay > 400) { |
| + // Speed up if idle notifications are rare. |
|
Erik Corry
2011/11/10 15:06:55
Time-based things make debugging difficult, and in
ulan
2011/11/11 13:27:26
As discussed offline, added a "hint" argument to I
|
| + step_size *= 10; |
| + } |
| + |
| + if (incremental_marking()->IsStopped()) { |
| + if (!old_data_space()->IsSweepingComplete() || |
| + !old_pointer_space()->IsSweepingComplete()) { |
|
Erik Corry
2011/11/10 15:06:55
It is a little dangerous to name individual spaces
ulan
2011/11/11 13:27:26
Done.
|
| + bool sweeping_complete = old_data_space()->AdvanceSweeper(step_size); |
| + sweeping_complete &= old_pointer_space()->AdvanceSweeper(step_size); |
| + if (!sweeping_complete) { |
| + return false; |
| + } |
| + } |
| + if (!WorthStartingGCWhenIdle()) { |
| + return true; |
| + } |
| + incremental_marking()->Start(); |
| + } |
| + |
| + // This flag prevents incremental marking from requesting GC via stack guard |
| + // and also prevents GC from starting a new incremental marking. |
| + idle_notification_will_schedule_next_gc_ = true; |
| + |
| + incremental_marking()->Step(step_size); |
|
Erik Corry
2011/11/10 15:06:55
It seems that we do a step without checking that w
ulan
2011/11/11 13:27:26
Line 4513 starts marking if it is not started alre
|
| + |
| + if (incremental_marking()->IsComplete()) { |
| + bool uncommit = false; |
| + if (last_idle_notification_gc_count_ - gc_count_ < kGCsBetweenCleanup / 2) { |
| + // Mutator was idle since the the last GC caused by IdleNotification. |
| + isolate_->compilation_cache()->Clear(); |
|
Erik Corry
2011/11/10 15:06:55
We seem to be duplicating a lot of the logic of in
ulan
2011/11/11 13:27:26
We do it in LowMemoryNotification and in old versi
|
| + uncommit = true; |
| + } |
| + CollectAllGarbage(kNoGCFlags); |
| + if (uncommit) { |
| + new_space_.Shrink(); |
| + UncommitFromSpace(); |
| + } |
| + last_idle_notification_gc_count_ = gc_count_; |
| + number_idle_notifications_++; |
| + } |
| + |
| + idle_notification_will_schedule_next_gc_ = false; |
| + |
| + return !WorthStartingGCWhenIdle() && |
|
Erik Corry
2011/11/10 15:06:55
If it is worth starting, should we not just start
ulan
2011/11/11 13:27:26
Now I am simply returning false, so the next notif
|
| + incremental_marking()->IsStopped() && |
| + old_data_space()->IsSweepingComplete() && |
|
Erik Corry
2011/11/10 15:06:55
Listing the lazily swept pages is fragile.
ulan
2011/11/11 13:27:26
Done.
|
| + old_pointer_space()->IsSweepingComplete(); |
| +} |
| + |
| + |
| +bool Heap::IdleGlobalGC() { |
| bool uncommit = true; |
| bool finished = false; |