Index: Source/platform/heap/ThreadState.cpp |
diff --git a/Source/platform/heap/ThreadState.cpp b/Source/platform/heap/ThreadState.cpp |
index 7c857b9c609fc6962df5e713383dcfff6424b36c..d7c104263a1b4cd8216c13a959ae6972009fe51e 100644 |
--- a/Source/platform/heap/ThreadState.cpp |
+++ b/Source/platform/heap/ThreadState.cpp |
@@ -97,8 +97,8 @@ ThreadState::ThreadState() |
, m_sweepForbidden(false) |
, m_noAllocationCount(0) |
, m_gcForbiddenCount(0) |
- , m_persistentAllocated(0) |
- , m_persistentFreed(0) |
+ , m_wrapperAllocated(0) |
+ , m_wrapperFreed(0) |
, m_vectorBackingHeapIndex(Vector1HeapIndex) |
, m_currentHeapAges(0) |
, m_isTerminating(false) |
@@ -558,110 +558,82 @@ CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion() |
return persistentRegion; |
} |
-void ThreadState::updatePersistentCounters() |
+void ThreadState::updateWrapperCounters() |
{ |
- if (m_persistentAllocated >= m_persistentFreed) |
- Heap::increasePersistentCount(m_persistentAllocated - m_persistentFreed); |
+ if (m_wrapperAllocated >= m_wrapperFreed) |
+ Heap::increaseWrapperCount(m_wrapperAllocated - m_wrapperFreed); |
else |
- Heap::decreasePersistentCount(m_persistentFreed - m_persistentAllocated); |
- Heap::increaseCollectedPersistentCount(m_persistentFreed); |
- m_persistentAllocated = 0; |
- m_persistentFreed = 0; |
-} |
- |
-size_t ThreadState::estimatedLiveObjectSize() |
-{ |
- // We estimate the live object size with the following equations. |
- // |
- // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persistentCount(t0) |
- // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionAlloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) |
- // |
- // t0: The time when the last collectGarbage runs. |
- // t1: The time when the last completeSweep runs. |
- // t: The current time. |
- // marked(t0, t): The size of marked objects between t0 and t. |
- // allocated(t0, t): The size of newly allocated objects between t0 and t. |
- // persistentCount(t): The number of existing persistent handles at t. |
- // collectedPersistentCount(t0, t): |
- // The number of persistent handles collected between |
- // t0 and t. |
- // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t. |
- size_t currentHeapSize = currentObjectSize(); |
- size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent() * Heap::collectedPersistentCount(); |
- size_t estimatedSize = 0; |
- if (currentHeapSize > heapSizeRetainedByCollectedPersistents) |
- estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents; |
- TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(currentHeapSize / 1024, static_cast<size_t>(INT_MAX))); |
- TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::min(estimatedSize / 1024, static_cast<size_t>(INT_MAX))); |
- TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(100.0 * currentHeapSize / estimatedSize)); |
- return estimatedSize; |
-} |
- |
-size_t ThreadState::currentObjectSize() |
-{ |
- return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
+ Heap::decreaseWrapperCount(m_wrapperFreed - m_wrapperAllocated); |
+ Heap::increaseCollectedWrapperCount(m_wrapperFreed); |
+ m_wrapperAllocated = 0; |
+ m_wrapperFreed = 0; |
} |
-bool ThreadState::shouldForceMemoryPressureGC() |
+double ThreadState::partitionAllocGrowingRate() |
{ |
- // Avoid potential overflow by truncating to Kb. |
- size_t currentObjectSizeKb = currentObjectSize() >> 10; |
- if (currentObjectSizeKb < 300 * 1024) |
+ size_t sizeAtLastGC = Heap::partitionAllocSizeAtLastGC(); |
+ size_t wrapperCountAtLastGC = Heap::wrapperCountAtLastGC(); |
+ size_t sizeRetainedByCollectedPersistents = wrapperCountAtLastGC ? Heap::collectedWrapperCount() * sizeAtLastGC / wrapperCountAtLastGC : 0; |
+ size_t estimatedLiveSize = sizeAtLastGC > sizeRetainedByCollectedPersistents ? sizeAtLastGC - sizeRetainedByCollectedPersistents : 0; |
+ double growingRate = estimatedLiveSize ? 1.0 * WTF::Partitions::totalSizeOfCommittedPages() / estimatedLiveSize : 0; |
+ TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLivePartitionAllocSizeKB", std::min(estimatedLiveSize / 1024, static_cast<size_t>(INT_MAX))); |
+ TRACE_COUNTER1("blink_gc", "ThreadState::partitionAllocGrowingRate", static_cast<int>(100 * growingRate)); |
+ return growingRate; |
+} |
+ |
+double ThreadState::heapGrowingRate() |
+{ |
+ size_t markedObjectSize = Heap::markedObjectSizeAtLastCompleteSweep(); |
+ size_t currentObjectSize = Heap::allocatedObjectSize() + markedObjectSize; |
+ double growingRate = markedObjectSize ? 1.0 * currentObjectSize / markedObjectSize : 0; |
+ TRACE_COUNTER1("blink_gc", "ThreadState::currentObjectSizeKB", std::min(currentObjectSize / 1024, static_cast<size_t>(INT_MAX))); |
+ TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(100 * growingRate)); |
+ return growingRate; |
+} |
+ |
+// TODO(haraken): We should improve the GC heuristics. These heuristics |
+// significantly affect performance. |
+bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double heapGrowingRateThreshold, double partitionAllocGrowingRateThreshold) |
+{ |
+ if (Heap::allocatedObjectSize() < allocatedObjectSizeThreshold) |
return false; |
+ if (heapGrowingRate() >= heapGrowingRateThreshold) |
+ return true; |
+ return partitionAllocGrowingRate() >= partitionAllocGrowingRateThreshold; |
+} |
- size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; |
- // If we're consuming too much memory, trigger a conservative GC |
- // aggressively. This is a safe guard to avoid OOM. |
- return currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2; |
+bool ThreadState::shouldForceMemoryPressureGC() |
+{ |
+ size_t totalObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectSizeAtLastCompleteSweep() + WTF::Partitions::totalSizeOfCommittedPages(); |
+ if (totalObjectSize < 300 * 1024 * 1024) |
+ return false; |
+ return judgeGCThreshold(0, 1.5, 1.5); |
} |
-// TODO(haraken): We should improve the GC heuristics. |
-// These heuristics affect performance significantly. |
bool ThreadState::shouldScheduleIdleGC() |
{ |
if (gcState() != NoGCScheduled) |
return false; |
#if ENABLE(IDLE_GC) |
- // Avoid potential overflow by truncating to Kb. |
- size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; |
- // The estimated size is updated when the main thread finishes lazy |
- // sweeping. If this thread reaches here before the main thread finishes |
- // lazy sweeping, the thread will use the estimated size of the last GC. |
- size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; |
- // Heap::markedObjectSize() may be underestimated if any thread has not |
- // finished completeSweep(). |
- size_t currentObjectSizeKb = currentObjectSize() >> 10; |
- // Schedule an idle GC if Oilpan has allocated more than 1 MB since |
- // the last GC and the current memory usage is >50% larger than |
- // the estimated live memory usage. |
- return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2; |
+ return judgeGCThreshold(1024 * 1024, 1.5, 1.5); |
#else |
return false; |
#endif |
} |
-// TODO(haraken): We should improve the GC heuristics. |
-// These heuristics affect performance significantly. |
bool ThreadState::shouldSchedulePreciseGC() |
{ |
- if (gcState() != NoGCScheduled) |
+ if (isGCForbidden()) |
return false; |
+ |
+ if (shouldForceMemoryPressureGC()) |
+ return true; |
+ |
#if ENABLE(IDLE_GC) |
- return false; |
+ return judgeGCThreshold(32 * 1024 * 1024, 4.0, 4.0); |
+ // return false; |
#else |
- // Avoid potential overflow by truncating to Kb. |
- size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; |
- // The estimated size is updated when the main thread finishes lazy |
- // sweeping. If this thread reaches here before the main thread finishes |
- // lazy sweeping, the thread will use the estimated size of the last GC. |
- size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; |
- // Heap::markedObjectSize() may be underestimated if any thread has not |
- // finished completeSweep(). |
- size_t currentObjectSizeKb = currentObjectSize() >> 10; |
- // Schedule a precise GC if Oilpan has allocated more than 1 MB since |
- // the last GC and the current memory usage is >50% larger than |
- // the estimated live memory usage. |
- return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2; |
+ return judgeGCThreshold(1024 * 1024, 1.5, 1.5); |
#endif |
} |
@@ -714,26 +686,13 @@ void ThreadState::schedulePageNavigationGC() |
// These heuristics affect performance significantly. |
bool ThreadState::shouldForceConservativeGC() |
{ |
- if (UNLIKELY(isGCForbidden())) |
+ if (isGCForbidden()) |
return false; |
if (shouldForceMemoryPressureGC()) |
return true; |
- // Avoid potential overflow by truncating to Kb. |
- size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; |
- // The estimated size is updated when the main thread finishes lazy |
- // sweeping. If this thread reaches here before the main thread finishes |
- // lazy sweeping, the thread will use the estimated size of the last GC. |
- size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; |
- // Heap::markedObjectSize() may be underestimated if any thread has not |
- // finished completeSweep(). |
- size_t currentObjectSizeKb = currentObjectSize() >> 10; |
- // Schedule a conservative GC if Oilpan has allocated more than 32 MB since |
- // the last GC and the current memory usage is >400% larger than |
- // the estimated live memory usage. |
- // TODO(haraken): 400% is too large. Lower the heap growing factor. |
- return allocatedObjectSizeKb >= 32 * 1024 && currentObjectSizeKb > 5 * estimatedLiveObjectSizeKb; |
+ return judgeGCThreshold(32 * 1024 * 1024, 5.0, 5.0); |
} |
void ThreadState::scheduleGCIfNeeded() |
@@ -938,18 +897,6 @@ ThreadState::GCState ThreadState::gcState() const |
return m_gcState; |
} |
-void ThreadState::didV8MajorGC() |
-{ |
- ASSERT(checkThread()); |
- if (isMainThread()) { |
- if (shouldForceMemoryPressureGC()) { |
- // Under memory pressure, force a conservative GC. |
- Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::ConservativeGC); |
- return; |
- } |
- } |
-} |
- |
void ThreadState::runScheduledGC(StackState stackState) |
{ |
ASSERT(checkThread()); |
@@ -1012,7 +959,7 @@ void ThreadState::preGC() |
makeConsistentForGC(); |
flushHeapDoesNotContainCacheIfNeeded(); |
clearHeapAges(); |
- updatePersistentCounters(); |
+ updateWrapperCounters(); |
} |
void ThreadState::postGC(GCType gcType) |
@@ -1193,14 +1140,11 @@ void ThreadState::postSweep() |
Heap::reportMemoryUsageForTracing(); |
if (isMainThread()) { |
- // See the comment in estimatedLiveObjectSize() for what we're |
- // calculating here. |
- // |
// Heap::markedObjectSize() may be underestimated here if any other |
// thread has not yet finished lazy sweeping. |
- if (Heap::persistentCountAtLastGC() > 0) { |
- TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate", 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC()); |
- Heap::setHeapSizePerPersistent((Heap::markedObjectSize() + Heap::partitionAllocSizeAtLastGC()) / Heap::persistentCountAtLastGC()); |
+ if (Heap::objectSizeAtLastGC()) { |
+ TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate", 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC()); |
+ Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize()); |
} |
} |