void V8GCController::gcEpilogue(v8::GCType type, v8::GCCallbackFlags flags) { // FIXME: It would be nice if the GC callbacks passed the Isolate directly.... v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (type == v8::kGCTypeScavenge) minorGCEpilogue(isolate); else if (type == v8::kGCTypeMarkSweepCompact) majorGCEpilogue(isolate); // Forces a Blink heap garbage collection when a garbage collection // was forced from V8. This is used for tests that force GCs from // JavaScript to verify that objects die when expected. if (flags & v8::kGCCallbackFlagForced) { // This single GC is not enough for two reasons: // (1) The GC is not precise because the GC scans on-stack pointers conservatively. // (2) One GC is not enough to break a chain of persistent handles. It's possible that // some heap allocated objects own objects that contain persistent handles // pointing to other heap allocated objects. To break the chain, we need multiple GCs. // // Regarding (1), we force a precise GC at the end of the current event loop. So if you want // to collect all garbage, you need to wait until the next event loop. // Regarding (2), it would be OK in practice to trigger only one GC per gcEpilogue, because // GCController.collectAll() forces 7 V8's GC. Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::ForcedGC); // Forces a precise GC at the end of the current event loop. Heap::setForcePreciseGCForTesting(); } TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GCEvent", "usedHeapSizeAfter", usedHeapSize(isolate)); TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data()); }
void V8GCController::gcEpilogue(v8::Isolate* isolate, v8::GCType type, v8::GCCallbackFlags flags) { switch (type) { case v8::kGCTypeScavenge: TRACE_EVENT_END1("devtools.timeline,v8", "MinorGC", "usedHeapSizeAfter", usedHeapSize(isolate)); // TODO(haraken): Remove this. See the comment in gcPrologue. if (ThreadState::current()) ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MinorGC); break; case v8::kGCTypeMarkSweepCompact: TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate)); if (ThreadState::current()) ThreadState::current()->scheduleV8FollowupGCIfNeeded(BlinkGC::V8MajorGC); break; case v8::kGCTypeIncrementalMarking: TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate)); break; case v8::kGCTypeProcessWeakCallbacks: TRACE_EVENT_END1("devtools.timeline,v8", "MajorGC", "usedHeapSizeAfter", usedHeapSize(isolate)); break; default: ASSERT_NOT_REACHED(); } if (isMainThread()) ScriptForbiddenScope::exit(); // v8::kGCCallbackFlagForced forces a Blink heap garbage collection // when a garbage collection was forced from V8. This is either used // for tests that force GCs from JavaScript to verify that objects die // when expected. if (flags & v8::kGCCallbackFlagForced) { // This single GC is not enough for two reasons: // (1) The GC is not precise because the GC scans on-stack pointers conservatively. // (2) One GC is not enough to break a chain of persistent handles. It's possible that // some heap allocated objects own objects that contain persistent handles // pointing to other heap allocated objects. To break the chain, we need multiple GCs. // // Regarding (1), we force a precise GC at the end of the current event loop. So if you want // to collect all garbage, you need to wait until the next event loop. // Regarding (2), it would be OK in practice to trigger only one GC per gcEpilogue, because // GCController.collectAll() forces multiple V8's GC. Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::ForcedGC); // Forces a precise GC at the end of the current event loop. if (ThreadState::current()) { RELEASE_ASSERT(!ThreadState::current()->isInGC()); ThreadState::current()->setGCState(ThreadState::FullGCScheduled); } } // v8::kGCCallbackFlagCollectAllAvailableGarbage is used when V8 handles // low memory notifications. if (flags & v8::kGCCallbackFlagCollectAllAvailableGarbage) { // This single GC is not enough. See the above comment. Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::ForcedGC); // Do not force a precise GC at the end of the current event loop. // According to UMA stats, the collection rate of the precise GC // scheduled at the end of the low memory handling is extremely low, // because the above conservative GC is sufficient for collecting // most objects. So we intentionally don't schedule a precise GC here. } TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", InspectorUpdateCountersEvent::data()); }