Heap::Heap(VM* vm, HeapType heapType) : m_heapType(heapType) , m_ramSize(ramSize()) , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize)) , m_sizeAfterLastCollect(0) , m_bytesAllocatedLimit(m_minBytesPerCycle) , m_bytesAllocated(0) , m_bytesAbandoned(0) , m_totalBytesVisited(0) , m_totalBytesCopied(0) , m_operationInProgress(NoOperation) , m_blockAllocator() , m_objectSpace(this) , m_storageSpace(this) , m_extraMemoryUsage(0) , m_machineThreads(this) , m_sharedData(vm) , m_slotVisitor(m_sharedData) , m_copyVisitor(m_sharedData) , m_handleSet(vm) , m_isSafeToCollect(false) , m_vm(vm) , m_lastGCLength(0) , m_lastCodeDiscardTime(WTF::monotonicallyIncreasingTime()) , m_activityCallback(DefaultGCActivityCallback::create(this)) , m_sweeper(IncrementalSweeper::create(this)) , m_deferralDepth(0) { m_storageSpace.init(); }
Heap::Heap(JSGlobalData* globalData, HeapType heapType) : m_heapType(heapType) , m_ramSize(ramSize()) , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize)) , m_sizeAfterLastCollect(0) , m_bytesAllocatedLimit(m_minBytesPerCycle) , m_bytesAllocated(0) , m_bytesAbandoned(0) , m_operationInProgress(NoOperation) , m_blockAllocator() , m_objectSpace(this) , m_storageSpace(this) , m_machineThreads(this) , m_sharedData(globalData) , m_slotVisitor(m_sharedData) , m_copyVisitor(m_sharedData) , m_handleSet(globalData) , m_isSafeToCollect(false) , m_globalData(globalData) , m_lastGCLength(0) , m_lastCodeDiscardTime(WTF::currentTime()) , m_activityCallback(DefaultGCActivityCallback::create(this)) , m_sweeper(IncrementalSweeper::create(this)) { m_storageSpace.init(); }
Heap::Heap(VM* vm, HeapType heapType) : m_heapType(heapType) , m_ramSize(Options::forceRAMSize() ? Options::forceRAMSize() : ramSize()) , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize)) , m_sizeAfterLastCollect(0) , m_sizeAfterLastFullCollect(0) , m_sizeBeforeLastFullCollect(0) , m_sizeAfterLastEdenCollect(0) , m_sizeBeforeLastEdenCollect(0) , m_bytesAllocatedThisCycle(0) , m_bytesAbandonedSinceLastFullCollect(0) , m_maxEdenSize(m_minBytesPerCycle) , m_maxHeapSize(m_minBytesPerCycle) , m_shouldDoFullCollection(false) , m_totalBytesVisited(0) , m_totalBytesCopied(0) , m_operationInProgress(NoOperation) , m_objectSpace(this) , m_storageSpace(this) , m_extraMemorySize(0) , m_deprecatedExtraMemorySize(0) , m_machineThreads(this) , m_sharedData(vm) , m_slotVisitor(m_sharedData) , m_copyVisitor(m_sharedData) , m_handleSet(vm) , m_isSafeToCollect(false) , m_writeBarrierBuffer(256) , m_vm(vm) // We seed with 10ms so that GCActivityCallback::didAllocate doesn't continuously // schedule the timer if we've never done a collection. , m_lastFullGCLength(0.01) , m_lastEdenGCLength(0.01) , m_fullActivityCallback(GCActivityCallback::createFullTimer(this)) #if ENABLE(GGC) , m_edenActivityCallback(GCActivityCallback::createEdenTimer(this)) #else , m_edenActivityCallback(m_fullActivityCallback) #endif #if USE(CF) , m_sweeper(std::make_unique<IncrementalSweeper>(this, CFRunLoopGetCurrent())) #else , m_sweeper(std::make_unique<IncrementalSweeper>(this->vm())) #endif , m_deferralDepth(0) #if USE(CF) , m_delayedReleaseRecursionCount(0) #endif { m_storageSpace.init(); if (Options::verifyHeap()) m_verifier = std::make_unique<HeapVerifier>(this, Options::numberOfGCCyclesToRecordForVerification()); }
void Heap::updateAllocationLimits() { GCPHASE(UpdateAllocationLimits); size_t currentHeapSize = sizeAfterCollect(); if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize()) HeapStatistics::exitWithFailure(); if (m_operationInProgress == FullCollection) { // 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. m_maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize)); m_maxEdenSize = m_maxHeapSize - currentHeapSize; m_sizeAfterLastFullCollect = currentHeapSize; m_bytesAbandonedSinceLastFullCollect = 0; } else { ASSERT(currentHeapSize >= m_sizeAfterLastCollect); m_maxEdenSize = m_maxHeapSize - currentHeapSize; m_sizeAfterLastEdenCollect = currentHeapSize; double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize; double minEdenToOldGenerationRatio = 1.0 / 3.0; if (edenToOldGenerationRatio < minEdenToOldGenerationRatio) m_shouldDoFullCollection = true; m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect; m_maxEdenSize = m_maxHeapSize - currentHeapSize; if (m_fullActivityCallback) { ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect); m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect); } } m_sizeAfterLastCollect = currentHeapSize; m_bytesAllocatedThisCycle = 0; if (Options::logGC()) dataLog(currentHeapSize / 1024, " kb, "); }
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); }