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; |