void Heap::collect(SweepToggle sweepToggle) { #if ENABLE(ALLOCATION_LOGGING) dataLogF("JSC GC starting collection.\n"); #endif double before = 0; if (Options::logGC()) { dataLog("[GC", sweepToggle == DoSweep ? " (eager sweep)" : "", ": "); before = currentTimeMS(); } SamplingRegion samplingRegion("Garbage Collection"); RELEASE_ASSERT(!m_deferralDepth); GCPHASE(Collect); ASSERT(vm()->currentThreadIsHoldingAPILock()); RELEASE_ASSERT(vm()->identifierTable == wtfThreadData().currentIdentifierTable()); ASSERT(m_isSafeToCollect); JAVASCRIPTCORE_GC_BEGIN(); RELEASE_ASSERT(m_operationInProgress == NoOperation); m_deferralDepth++; // Make sure that we don't GC in this call. m_vm->prepareToDiscardCode(); m_deferralDepth--; // Decrement deferal manually, so we don't GC when we do so, since we are already GCing!. m_operationInProgress = Collection; m_extraMemoryUsage = 0; if (m_activityCallback) m_activityCallback->willCollect(); double lastGCStartTime = WTF::monotonicallyIncreasingTime(); if (lastGCStartTime - m_lastCodeDiscardTime > minute) { deleteAllCompiledCode(); m_lastCodeDiscardTime = WTF::monotonicallyIncreasingTime(); } { GCPHASE(StopAllocation); m_objectSpace.stopAllocating(); } markRoots(); { GCPHASE(ReapingWeakHandles); m_objectSpace.reapWeakSets(); } JAVASCRIPTCORE_GC_MARKED(); { GCPHASE(SweepingArrayBuffers); m_arrayBuffers.sweep(); } { m_blockSnapshot.resize(m_objectSpace.blocks().set().size()); MarkedBlockSnapshotFunctor functor(m_blockSnapshot); m_objectSpace.forEachBlock(functor); } copyBackingStores(); { GCPHASE(FinalizeUnconditionalFinalizers); finalizeUnconditionalFinalizers(); } { GCPHASE(DeleteCodeBlocks); deleteUnmarkedCompiledCode(); } { GCPHASE(DeleteSourceProviderCaches); m_vm->clearSourceProviderCaches(); } if (sweepToggle == DoSweep) { SamplingRegion samplingRegion("Garbage Collection: Sweeping"); GCPHASE(Sweeping); m_objectSpace.sweep(); m_objectSpace.shrink(); } m_sweeper->startSweeping(m_blockSnapshot); m_bytesAbandoned = 0; { GCPHASE(ResetAllocators); m_objectSpace.resetAllocators(); } size_t currentHeapSize = sizeAfterCollect(); if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize()) HeapStatistics::exitWithFailure(); m_sizeAfterLastCollect = currentHeapSize; // To avoid pathological GC churn in very small and very large heaps, we set // the new allocation limit based on the current size of the heap, with a // fixed minimum. size_t maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize)); m_bytesAllocatedLimit = maxHeapSize - currentHeapSize; m_bytesAllocated = 0; double lastGCEndTime = WTF::monotonicallyIncreasingTime(); m_lastGCLength = lastGCEndTime - lastGCStartTime; if (Options::recordGCPauseTimes()) HeapStatistics::recordGCPauseTime(lastGCStartTime, lastGCEndTime); RELEASE_ASSERT(m_operationInProgress == Collection); m_operationInProgress = NoOperation; JAVASCRIPTCORE_GC_END(); if (Options::useZombieMode()) zombifyDeadObjects(); if (Options::objectsAreImmortal()) markDeadObjects(); if (Options::showObjectStatistics()) HeapStatistics::showObjectStatistics(this); if (Options::logGC()) { double after = currentTimeMS(); dataLog(after - before, " ms, ", currentHeapSize / 1024, " kb]\n"); } #if ENABLE(ALLOCATION_LOGGING) dataLogF("JSC GC finishing collection.\n"); #endif }
void Heap::collect(SweepToggle sweepToggle) { SamplingRegion samplingRegion("Garbage Collection"); GCPHASE(Collect); ASSERT(globalData()->apiLock().currentThreadIsHoldingLock()); RELEASE_ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); ASSERT(m_isSafeToCollect); JAVASCRIPTCORE_GC_BEGIN(); RELEASE_ASSERT(m_operationInProgress == NoOperation); m_operationInProgress = Collection; m_activityCallback->willCollect(); double lastGCStartTime = WTF::currentTime(); if (lastGCStartTime - m_lastCodeDiscardTime > minute) { deleteAllCompiledCode(); m_lastCodeDiscardTime = WTF::currentTime(); } { GCPHASE(Canonicalize); m_objectSpace.canonicalizeCellLivenessData(); } markRoots(); { GCPHASE(ReapingWeakHandles); m_objectSpace.reapWeakSets(); } JAVASCRIPTCORE_GC_MARKED(); { m_blockSnapshot.resize(m_objectSpace.blocks().set().size()); MarkedBlockSnapshotFunctor functor(m_blockSnapshot); m_objectSpace.forEachBlock(functor); } copyBackingStores(); { GCPHASE(FinalizeUnconditionalFinalizers); finalizeUnconditionalFinalizers(); } { GCPHASE(finalizeSmallStrings); m_globalData->smallStrings.finalizeSmallStrings(); } { GCPHASE(DeleteCodeBlocks); deleteUnmarkedCompiledCode(); } { GCPHASE(DeleteSourceProviderCaches); m_globalData->clearSourceProviderCaches(); } if (sweepToggle == DoSweep) { SamplingRegion samplingRegion("Garbage Collection: Sweeping"); GCPHASE(Sweeping); m_objectSpace.sweep(); m_objectSpace.shrink(); } m_sweeper->startSweeping(m_blockSnapshot); m_bytesAbandoned = 0; { GCPHASE(ResetAllocators); m_objectSpace.resetAllocators(); } size_t currentHeapSize = size(); if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize()) HeapStatistics::exitWithFailure(); m_sizeAfterLastCollect = currentHeapSize; // To avoid pathological GC churn in very small and very large heaps, we set // the new allocation limit based on the current size of the heap, with a // fixed minimum. size_t maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize)); m_bytesAllocatedLimit = maxHeapSize - currentHeapSize; m_bytesAllocated = 0; double lastGCEndTime = WTF::currentTime(); m_lastGCLength = lastGCEndTime - lastGCStartTime; if (Options::recordGCPauseTimes()) HeapStatistics::recordGCPauseTime(lastGCStartTime, lastGCEndTime); RELEASE_ASSERT(m_operationInProgress == Collection); m_operationInProgress = NoOperation; JAVASCRIPTCORE_GC_END(); if (Options::useZombieMode()) zombifyDeadObjects(); if (Options::objectsAreImmortal()) markDeadObjects(); if (Options::showObjectStatistics()) HeapStatistics::showObjectStatistics(this); }