From 6f3c50460ae348c6e4b9ac2169f818a8fb7fa3c8 Mon Sep 17 00:00:00 2001 From: "mike@belshe.com" Date: Tue, 25 Aug 2009 02:54:39 +0000 Subject: [PATCH] Update the Idle collector to do a full GC after being idle for some time. Remove the default argument from CollectAllGarbage. Review URL: http://codereview.chromium.org/174302 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2748 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 6 +++++- src/api.cc | 6 +++--- src/debug.cc | 6 +++--- src/execution.cc | 2 +- src/heap-inl.h | 4 ++-- src/heap.cc | 2 +- src/heap.h | 35 ++++++++++++++++++++++++++++++++++- src/mksnapshot.cc | 2 +- src/runtime.cc | 6 +++--- src/v8.cc | 10 +++++----- src/v8.h | 2 +- 11 files changed, 59 insertions(+), 22 deletions(-) diff --git a/include/v8.h b/include/v8.h index c7cc3154ab..a40c068ed5 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2280,9 +2280,13 @@ class V8EXPORT V8 { /** * Optional notification that the embedder is idle. * V8 uses the notification to reduce memory footprint. + * This call can be used repeatedly if the embedder remains idle. * \param is_high_priority tells whether the embedder is high priority. + * Returns true if the embedder should stop calling IdleNotification + * until real work has been done. This indicates that V8 has done + * as much cleanup as it will be able to do. */ - static void IdleNotification(bool is_high_priority); + static bool IdleNotification(bool is_high_priority); /** * Optional notification that the system is running low on memory. diff --git a/src/api.cc b/src/api.cc index 7d97fc658c..bb38356ec5 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2604,8 +2604,8 @@ bool v8::V8::Dispose() { } -void v8::V8::IdleNotification(bool is_high_priority) { - i::V8::IdleNotification(is_high_priority); +bool v8::V8::IdleNotification(bool is_high_priority) { + return i::V8::IdleNotification(is_high_priority); } @@ -3335,7 +3335,7 @@ void V8::ResumeProfilerEx(int flags) { flags &= ~(PROFILER_MODULE_HEAP_SNAPSHOT | PROFILER_MODULE_CPU); const int current_flags = i::Logger::GetActiveProfilerModules(); i::Logger::ResumeProfiler(flags); - i::Heap::CollectAllGarbage(); + i::Heap::CollectAllGarbage(false); i::Logger::PauseProfiler(~current_flags & flags); } else { i::Logger::ResumeProfiler(flags); diff --git a/src/debug.cc b/src/debug.cc index f2a28148b1..faeb29ba46 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1548,8 +1548,8 @@ void Debug::CreateScriptCache() { // Perform two GCs to get rid of all unreferenced scripts. The first GC gets // rid of all the cached script wrappers and the second gets rid of the // scripts which is no longer referenced. - Heap::CollectAllGarbage(); - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); + Heap::CollectAllGarbage(false); ASSERT(script_cache_ == NULL); script_cache_ = new ScriptCache(); @@ -1599,7 +1599,7 @@ Handle Debug::GetLoadedScripts() { // Perform GC to get unreferenced scripts evicted from the cache before // returning the content. - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); // Get the scripts from the cache. return script_cache_->GetScripts(); diff --git a/src/execution.cc b/src/execution.cc index 0ad55bd558..7c42e5e74b 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -677,7 +677,7 @@ v8::Handle GCExtension::GetNativeFunction( v8::Handle GCExtension::GC(const v8::Arguments& args) { // All allocation spaces other than NEW_SPACE have the same effect. - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); return v8::Undefined(); } diff --git a/src/heap-inl.h b/src/heap-inl.h index 114ae0d4d1..0646878ef8 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -238,7 +238,7 @@ int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) { amount_of_external_allocated_memory_ - amount_of_external_allocated_memory_at_last_global_gc_; if (amount_since_last_global_gc > external_allocation_limit_) { - CollectAllGarbage(); + CollectAllGarbage(false); } } else { // Avoid underflow. @@ -285,7 +285,7 @@ void Heap::SetLastScriptId(Object* last_script_id) { } \ if (!__object__->IsRetryAfterGC()) RETURN_EMPTY; \ Counters::gc_last_resort_from_handles.Increment(); \ - Heap::CollectAllGarbage(); \ + Heap::CollectAllGarbage(false); \ { \ AlwaysAllocateScope __scope__; \ __object__ = FUNCTION_CALL; \ diff --git a/src/heap.cc b/src/heap.cc index f66766b885..ef4c2d4b08 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -332,7 +332,7 @@ void Heap::CollectAllGarbageIfContextDisposed() { // informed decisions about when to force a collection. if (!FLAG_expose_gc && context_disposed_pending_) { HistogramTimerScope scope(&Counters::gc_context); - CollectAllGarbage(); + CollectAllGarbage(false); } context_disposed_pending_ = false; } diff --git a/src/heap.h b/src/heap.h index 3763623ea5..9fd3fecb71 100644 --- a/src/heap.h +++ b/src/heap.h @@ -629,7 +629,7 @@ class Heap : public AllStatic { // Performs a full garbage collection. Force compaction if the // parameter is true. - static void CollectAllGarbage(bool force_compaction = false); + static void CollectAllGarbage(bool force_compaction); // Performs a full garbage collection if a context has been disposed // since the last time the check was performed. @@ -842,6 +842,39 @@ class Heap : public AllStatic { > old_gen_allocation_limit_; } + // Can be called when the embedding application is idle. + static bool IdleNotification() { + static const int kIdlesBeforeCollection = 7; + static int number_idle_notifications = 0; + static int last_gc_count = gc_count_; + + bool finished = false; + + if (last_gc_count == gc_count_) { + number_idle_notifications++; + } else { + number_idle_notifications = 0; + last_gc_count = gc_count_; + } + + if (number_idle_notifications >= kIdlesBeforeCollection) { + // The first time through we collect without forcing compaction. + // The second time through we force compaction and quit. + bool force_compaction = + number_idle_notifications > kIdlesBeforeCollection; + CollectAllGarbage(force_compaction); + last_gc_count = gc_count_; + if (force_compaction) { + number_idle_notifications = 0; + finished = true; + } + } + + // Uncommit unused memory in new space. + Heap::UncommitFromSpace(); + return finished; + } + // Declare all the root indices. enum RootListIndex { #define ROOT_INDEX_DECLARATION(type, name, camel_name) k##camel_name##RootIndex, diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc index 4891f375ae..80789ebbea 100644 --- a/src/mksnapshot.cc +++ b/src/mksnapshot.cc @@ -171,7 +171,7 @@ int main(int argc, char** argv) { } } // Get rid of unreferenced scripts with a global GC. - i::Heap::CollectAllGarbage(); + i::Heap::CollectAllGarbage(false); i::Serializer ser; ser.Serialize(); v8::internal::byte* bytes; diff --git a/src/runtime.cc b/src/runtime.cc index b3e8aa477d..845ac6308c 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7263,7 +7263,7 @@ static Object* Runtime_DebugReferencedBy(Arguments args) { ASSERT(args.length() == 3); // First perform a full GC in order to avoid references from dead objects. - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); // Check parameters. CONVERT_CHECKED(JSObject, target, args[0]); @@ -7339,7 +7339,7 @@ static Object* Runtime_DebugConstructedBy(Arguments args) { ASSERT(args.length() == 2); // First perform a full GC in order to avoid dead objects. - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); // Check parameters. CONVERT_CHECKED(JSFunction, constructor, args[0]); @@ -7633,7 +7633,7 @@ void Runtime::PerformGC(Object* result) { // Handle last resort GC and make sure to allow future allocations // to grow the heap without causing GCs (if possible). Counters::gc_last_resort_from_js.Increment(); - Heap::CollectAllGarbage(); + Heap::CollectAllGarbage(false); } } diff --git a/src/v8.cc b/src/v8.cc index faec986d38..bbcc9d1f1d 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -157,13 +157,13 @@ uint32_t V8::Random() { } -void V8::IdleNotification(bool is_high_priority) { - if (!FLAG_use_idle_notification) return; +bool V8::IdleNotification(bool is_high_priority) { + if (!FLAG_use_idle_notification) return false; // Ignore high priority instances of V8. - if (is_high_priority) return; + if (is_high_priority) return false; - // Uncommit unused memory in new space. - Heap::UncommitFromSpace(); + // Tell the heap that it may want to adjust. + return Heap::IdleNotification(); } diff --git a/src/v8.h b/src/v8.h index 1ca3245b9c..50be6df981 100644 --- a/src/v8.h +++ b/src/v8.h @@ -100,7 +100,7 @@ class V8 : public AllStatic { static Smi* RandomPositiveSmi(); // Idle notification directly from the API. - static void IdleNotification(bool is_high_priority); + static bool IdleNotification(bool is_high_priority); private: // True if engine is currently running