Index: Source/platform/heap/ThreadState.cpp |
diff --git a/Source/platform/heap/ThreadState.cpp b/Source/platform/heap/ThreadState.cpp |
index 04643aa4a33affe0e813b69822230af4f1ac6bfa..7ed2986a17c949a0a5a09d2c44f8d16593653a70 100644 |
--- a/Source/platform/heap/ThreadState.cpp |
+++ b/Source/platform/heap/ThreadState.cpp |
@@ -663,8 +663,8 @@ |
json->endArray(); |
#undef SNAPSHOT_HEAP |
- json->setInteger("allocatedSpace", Heap::allocatedSpace()); |
- json->setInteger("objectSpace", Heap::allocatedObjectSize()); |
+ json->setInteger("allocatedSpace", m_stats.totalAllocatedSpace()); |
+ json->setInteger("objectSpace", m_stats.totalObjectSpace()); |
json->setInteger("pageCount", info.pageCount); |
json->setInteger("freeSize", info.freeSize); |
@@ -731,35 +731,47 @@ |
return mutex; |
} |
+// Trigger garbage collection on a 50% increase in size, but not for |
+// less than 512kbytes. |
+bool ThreadState::increasedEnoughToGC(size_t newSize, size_t oldSize) |
+{ |
+ if (newSize < 1 << 19) |
+ return false; |
+ size_t limit = oldSize + (oldSize >> 1); |
+ return newSize > limit; |
+} |
+ |
+// FIXME: The heuristics are local for a thread at this |
+// point. Consider using heuristics that take memory for all threads |
+// into account. |
bool ThreadState::shouldGC() |
{ |
- // Do not GC during sweeping. We allow allocation during finalization, |
- // but those allocations are not allowed to lead to nested GCs. |
- if (m_sweepInProgress) |
+ // Do not GC during sweeping. We allow allocation during |
+ // finalization, but those allocations are not allowed |
+ // to lead to nested garbage collections. |
+ return !m_sweepInProgress && increasedEnoughToGC(m_stats.totalObjectSpace(), m_statsAfterLastGC.totalObjectSpace()); |
+} |
+ |
+// Trigger conservative garbage collection on a 100% increase in size, |
+// but not for less than 4Mbytes. If the system currently has a low |
+// collection rate, then require a 300% increase in size. |
+bool ThreadState::increasedEnoughToForceConservativeGC(size_t newSize, size_t oldSize) |
+{ |
+ if (newSize < 1 << 22) |
return false; |
- |
- // Trigger garbage collection on a 50% increase in size, |
- // but not for less than 512 KB. |
- if (Heap::allocatedObjectSize() < 1 << 19) |
- return false; |
- size_t limit = Heap::markedObjectSize() + Heap::markedObjectSize() / 2; |
- return Heap::allocatedObjectSize() > limit; |
-} |
- |
+ size_t limit = (m_lowCollectionRate ? 4 : 2) * oldSize; |
+ return newSize > limit; |
+} |
+ |
+// FIXME: The heuristics are local for a thread at this |
+// point. Consider using heuristics that take memory for all threads |
+// into account. |
bool ThreadState::shouldForceConservativeGC() |
{ |
- // Do not GC during sweeping. We allow allocation during finalization, |
- // but those allocations are not allowed to lead to nested GCs. |
- if (m_sweepInProgress) |
- return false; |
- |
- // Trigger conservative garbage collection on a 100% increase in size, |
- // but not for less than 4Mbytes. If the system currently has a low |
- // collection rate, then require a 300% increase in size. |
- if (Heap::allocatedObjectSize() < 1 << 22) |
- return false; |
- size_t limit = (m_lowCollectionRate ? 4 : 2) * Heap::markedObjectSize(); |
- return Heap::allocatedObjectSize() > limit; |
+ // Do not GC during sweeping. We allow allocation during |
+ // finalization, but those allocations are not allowed |
+ // to lead to nested garbage collections. |
+ return !m_sweepInProgress && increasedEnoughToForceConservativeGC(m_stats.totalObjectSpace(), m_statsAfterLastGC.totalObjectSpace()); |
} |
bool ThreadState::sweepRequested() |
@@ -892,13 +904,16 @@ |
return 0; |
} |
-size_t ThreadState::objectPayloadSizeForTesting() |
+void ThreadState::getStats(HeapStats& stats) |
+{ |
+ stats = m_stats; |
+} |
+ |
+void ThreadState::getStatsForTesting(HeapStats& stats) |
{ |
ASSERT(isConsistentForSweeping()); |
- size_t objectPayloadSize = 0; |
for (int i = 0; i < NumberOfHeaps; i++) |
- objectPayloadSize += m_heaps[i]->objectPayloadSizeForTesting(); |
- return objectPayloadSize; |
+ m_heaps[i]->getStatsForTesting(stats); |
} |
bool ThreadState::stopThreads() |
@@ -1027,9 +1042,10 @@ |
class SweepNonFinalizedHeapTask final : public WebThread::Task { |
public: |
- SweepNonFinalizedHeapTask(ThreadState* state, BaseHeap* heap) |
+ SweepNonFinalizedHeapTask(ThreadState* state, BaseHeap* heap, HeapStats* stats) |
: m_threadState(state) |
, m_heap(heap) |
+ , m_stats(stats) |
{ |
m_threadState->registerSweepingTask(); |
} |
@@ -1042,12 +1058,13 @@ |
virtual void run() |
{ |
TRACE_EVENT0("blink_gc", "ThreadState::sweepNonFinalizedHeaps"); |
- m_heap->sweep(); |
+ m_heap->sweep(m_stats); |
} |
private: |
ThreadState* m_threadState; |
BaseHeap* m_heap; |
+ HeapStats* m_stats; |
}; |
void ThreadState::performPendingSweep() |
@@ -1061,7 +1078,7 @@ |
// going to be freed. |
bool gcTracingEnabled; |
TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled); |
- if (gcTracingEnabled) |
+ if (gcTracingEnabled && m_stats.totalObjectSpace() > 0) |
snapshot(); |
#endif |
@@ -1074,7 +1091,7 @@ |
TRACE_EVENT_SET_SAMPLING_STATE("blink", "BlinkGCSweeping"); |
} |
- size_t allocatedObjectSizeBeforeSweeping = Heap::allocatedObjectSize(); |
+ size_t objectSpaceBeforeSweep = m_stats.totalObjectSpace(); |
{ |
NoSweepScope scope(this); |
@@ -1097,14 +1114,10 @@ |
clearGCRequested(); |
clearSweepRequested(); |
- |
- // If we collected less than 50% of objects, record that the collection rate |
- // is low which we use to determine when to perform the next GC. |
- // FIXME: We should make m_lowCollectionRate available in non-main threads. |
- // FIXME: Heap::markedObjectSize() may not be accurate because other threads |
- // may not have finished sweeping. |
- if (isMainThread()) |
- m_lowCollectionRate = Heap::markedObjectSize() > (allocatedObjectSizeBeforeSweeping / 2); |
+ // If we collected less than 50% of objects, record that the |
+ // collection rate is low which we use to determine when to |
+ // perform the next GC. |
+ setLowCollectionRate(m_stats.totalObjectSpace() > (objectSpaceBeforeSweep / 2)); |
if (Platform::current()) { |
Platform::current()->histogramCustomCounts("BlinkGC.PerformPendingSweep", WTF::currentTimeMS() - timeStamp, 0, 10 * 1000, 50); |
@@ -1118,6 +1131,9 @@ |
void ThreadState::performPendingSweepInParallel() |
{ |
+ // Sweeping will recalculate the stats |
+ m_stats.clear(); |
+ |
// Sweep the non-finalized heap pages on multiple threads. |
// Attempt to load-balance by having the sweeper thread sweep as |
// close to half of the pages as possible. |
@@ -1135,6 +1151,7 @@ |
// finalizers need to run and therefore the pages can be |
// swept on other threads. |
static const int minNumberOfPagesForParallelSweep = 10; |
+ HeapStats heapStatsVector[NumberOfNonFinalizedHeaps]; |
OwnPtr<BaseHeap> splitOffHeaps[NumberOfNonFinalizedHeaps]; |
for (int i = 0; i < NumberOfNonFinalizedHeaps && pagesToSweepInParallel > 0; i++) { |
BaseHeap* heap = m_heaps[FirstNonFinalizedHeap + i]; |
@@ -1148,7 +1165,8 @@ |
int pagesToSplitOff = std::min(pageCount, pagesToSweepInParallel); |
pagesToSweepInParallel -= pagesToSplitOff; |
splitOffHeaps[i] = heap->split(pagesToSplitOff); |
- m_sweeperThread->postTask(new SweepNonFinalizedHeapTask(this, splitOffHeaps[i].get())); |
+ HeapStats* stats = &heapStatsVector[i]; |
+ m_sweeperThread->postTask(new SweepNonFinalizedHeapTask(this, splitOffHeaps[i].get(), stats)); |
} |
} |
@@ -1157,7 +1175,9 @@ |
// if there is no sweeper thread). |
TRACE_EVENT0("blink_gc", "ThreadState::sweepNonFinalizedHeaps"); |
for (int i = 0; i < NumberOfNonFinalizedHeaps; i++) { |
- m_heaps[FirstNonFinalizedHeap + i]->sweep(); |
+ HeapStats stats; |
+ m_heaps[FirstNonFinalizedHeap + i]->sweep(&stats); |
+ m_stats.add(&stats); |
} |
} |
@@ -1165,18 +1185,25 @@ |
// Sweep the finalized pages. |
TRACE_EVENT0("blink_gc", "ThreadState::sweepFinalizedHeaps"); |
for (int i = 0; i < NumberOfFinalizedHeaps; i++) { |
- m_heaps[FirstFinalizedHeap + i]->sweep(); |
- } |
- } |
- |
+ HeapStats stats; |
+ m_heaps[FirstFinalizedHeap + i]->sweep(&stats); |
+ m_stats.add(&stats); |
+ } |
+ } |
+ |
+ // Wait for the sweeper threads and update the heap stats with the |
+ // stats for the heap portions swept by those threads. |
waitUntilSweepersDone(); |
for (int i = 0; i < NumberOfNonFinalizedHeaps; i++) { |
+ m_stats.add(&heapStatsVector[i]); |
if (splitOffHeaps[i]) |
m_heaps[FirstNonFinalizedHeap + i]->merge(splitOffHeaps[i].release()); |
} |
for (int i = 0; i < NumberOfHeaps; i++) |
m_heaps[i]->postSweepProcessing(); |
+ |
+ getStats(m_statsAfterLastGC); |
} |
void ThreadState::addInterruptor(Interruptor* interruptor) |