OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 m_persistentFreed = 0; | 569 m_persistentFreed = 0; |
570 } | 570 } |
571 | 571 |
572 size_t ThreadState::currentObjectSize() | 572 size_t ThreadState::currentObjectSize() |
573 { | 573 { |
574 return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partiti
ons::totalSizeOfCommittedPages(); | 574 return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partiti
ons::totalSizeOfCommittedPages(); |
575 } | 575 } |
576 | 576 |
577 size_t ThreadState::estimatedLiveObjectSize() | 577 size_t ThreadState::estimatedLiveObjectSize() |
578 { | 578 { |
| 579 if (Heap::persistentCountAtLastGC() == 0) { |
| 580 // We'll reach here only before hitting the first GC. |
| 581 return 0; |
| 582 } |
| 583 |
579 // We estimate the live object size with the following equations. | 584 // We estimate the live object size with the following equations. |
580 // | 585 // |
581 // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persist
entCount(t0) | 586 // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persist
entCount(t0) |
582 // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionA
lloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) | 587 // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionA
lloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) |
583 // | 588 // |
584 // t0: The time when the last collectGarbage runs. | 589 // t0: The time when the last collectGarbage runs. |
585 // t1: The time when the last completeSweep runs. | 590 // t1: The time when the last completeSweep runs. |
586 // t: The current time. | 591 // t: The current time. |
587 // marked(t0, t): The size of marked objects between t0 and t. | 592 // marked(t0, t): The size of marked objects between t0 and t. |
588 // allocated(t0, t): The size of newly allocated objects between t0 and t. | 593 // allocated(t0, t): The size of newly allocated objects between t0 and t. |
589 // persistentCount(t): The number of existing persistent handles at t. | 594 // persistentCount(t): The number of existing persistent handles at t. |
590 // collectedPersistentCount(t0, t): | 595 // collectedPersistentCount(t0, t): |
591 // The number of persistent handles collected between | 596 // The number of persistent handles collected between |
592 // t0 and t. | 597 // t0 and t. |
593 // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t. | 598 // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t. |
| 599 size_t heapSizeRetainedByCollectedPersistents = static_cast<size_t>(1.0 * (H
eap::markedObjectSizeAtLastCompleteSweep() + Heap::partitionAllocSizeAtLastGC())
/ Heap::persistentCountAtLastGC() * Heap::collectedPersistentCount()); |
594 size_t currentHeapSize = currentObjectSize(); | 600 size_t currentHeapSize = currentObjectSize(); |
595 size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent(
) * Heap::collectedPersistentCount(); | 601 if (currentHeapSize < heapSizeRetainedByCollectedPersistents) |
596 size_t estimatedSize = 0; | 602 return 0; |
597 if (currentHeapSize > heapSizeRetainedByCollectedPersistents) | 603 return currentHeapSize - heapSizeRetainedByCollectedPersistents; |
598 estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents
; | |
599 return estimatedSize; | |
600 } | 604 } |
601 | 605 |
602 double ThreadState::heapGrowingRate() | 606 double ThreadState::heapGrowingRate() |
603 { | 607 { |
604 size_t currentSize = currentObjectSize(); | 608 size_t currentSize = currentObjectSize(); |
605 size_t estimatedSize = estimatedLiveObjectSize(); | 609 size_t estimatedSize = estimatedLiveObjectSize(); |
606 double growingRate = 1.0 * currentSize / estimatedSize; | 610 // If the estimatedSize is 0, we set a very high growing rate |
| 611 // to trigger a GC. |
| 612 double growingRate = estimatedSize > 0 ? 1.0 * currentSize / estimatedSize :
100; |
607 TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(curren
tSize / 1024, static_cast<size_t>(INT_MAX))); | 613 TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(curren
tSize / 1024, static_cast<size_t>(INT_MAX))); |
608 TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::mi
n(estimatedSize / 1024, static_cast<size_t>(INT_MAX))); | 614 TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::mi
n(estimatedSize / 1024, static_cast<size_t>(INT_MAX))); |
609 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(
100 * growingRate)); | 615 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(
100 * growingRate)); |
610 return growingRate; | 616 return growingRate; |
611 } | 617 } |
612 | 618 |
613 // TODO(haraken): We should improve the GC heuristics. | 619 // TODO(haraken): We should improve the GC heuristics. |
614 // The heuristics affect performance significantly. | 620 // The heuristics affect performance significantly. |
615 bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double h
eapGrowingRateThreshold) | 621 bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double h
eapGrowingRateThreshold) |
616 { | 622 { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 return false; | 654 return false; |
649 #if ENABLE(IDLE_GC) | 655 #if ENABLE(IDLE_GC) |
650 return false; | 656 return false; |
651 #else | 657 #else |
652 return judgeGCThreshold(1024 * 1024, 1.5); | 658 return judgeGCThreshold(1024 * 1024, 1.5); |
653 #endif | 659 #endif |
654 } | 660 } |
655 | 661 |
656 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio) | 662 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio) |
657 { | 663 { |
658 if (isGCForbidden()) | |
659 return false; | |
660 | |
661 return judgeGCThreshold(1024 * 1024, 1.5); | 664 return judgeGCThreshold(1024 * 1024, 1.5); |
662 } | 665 } |
663 | 666 |
664 bool ThreadState::shouldForceConservativeGC() | 667 bool ThreadState::shouldForceConservativeGC() |
665 { | 668 { |
666 if (isGCForbidden()) | |
667 return false; | |
668 | |
669 // TODO(haraken): 400% is too large. Lower the heap growing factor. | 669 // TODO(haraken): 400% is too large. Lower the heap growing factor. |
670 return judgeGCThreshold(32 * 1024 * 1024, 5.0); | 670 return judgeGCThreshold(32 * 1024 * 1024, 5.0); |
671 } | 671 } |
672 | 672 |
673 void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) | 673 void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) |
674 { | 674 { |
675 ASSERT(checkThread()); | 675 ASSERT(checkThread()); |
| 676 if (isGCForbidden()) |
| 677 return; |
| 678 |
676 // Finish on-going lazy sweeping. | 679 // Finish on-going lazy sweeping. |
677 // TODO(haraken): It might not make sense to force completeSweep() for all | 680 // TODO(haraken): It might not make sense to force completeSweep() for all |
678 // page navigations. | 681 // page navigations. |
679 completeSweep(); | 682 completeSweep(); |
680 ASSERT(!isSweepingInProgress()); | 683 ASSERT(!isSweepingInProgress()); |
681 ASSERT(!sweepForbidden()); | 684 ASSERT(!sweepForbidden()); |
682 | 685 |
683 Heap::reportMemoryUsageForTracing(); | 686 Heap::reportMemoryUsageForTracing(); |
684 if (shouldSchedulePageNavigationGC(estimatedRemovalRatio)) | 687 if (shouldSchedulePageNavigationGC(estimatedRemovalRatio)) |
685 schedulePageNavigationGC(); | 688 schedulePageNavigationGC(); |
686 } | 689 } |
687 | 690 |
688 void ThreadState::schedulePageNavigationGC() | 691 void ThreadState::schedulePageNavigationGC() |
689 { | 692 { |
690 ASSERT(checkThread()); | 693 ASSERT(checkThread()); |
691 ASSERT(!isSweepingInProgress()); | 694 ASSERT(!isSweepingInProgress()); |
692 setGCState(PageNavigationGCScheduled); | 695 setGCState(PageNavigationGCScheduled); |
693 } | 696 } |
694 | 697 |
695 void ThreadState::scheduleGCIfNeeded() | 698 void ThreadState::scheduleGCIfNeeded() |
696 { | 699 { |
697 ASSERT(checkThread()); | 700 ASSERT(checkThread()); |
| 701 if (isGCForbidden()) |
| 702 return; |
| 703 |
698 // Allocation is allowed during sweeping, but those allocations should not | 704 // Allocation is allowed during sweeping, but those allocations should not |
699 // trigger nested GCs. | 705 // trigger nested GCs. |
700 if (isSweepingInProgress()) | 706 if (isSweepingInProgress()) |
701 return; | 707 return; |
702 ASSERT(!sweepForbidden()); | 708 ASSERT(!sweepForbidden()); |
703 | 709 |
704 Heap::reportMemoryUsageForTracing(); | 710 Heap::reportMemoryUsageForTracing(); |
705 | 711 |
706 if (shouldForceMemoryPressureGC()) { | 712 if (shouldForceMemoryPressureGC()) { |
707 Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::Conserva
tiveGC); | 713 Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::Conserva
tiveGC); |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1139 { | 1145 { |
1140 ASSERT(checkThread()); | 1146 ASSERT(checkThread()); |
1141 Heap::reportMemoryUsageForTracing(); | 1147 Heap::reportMemoryUsageForTracing(); |
1142 | 1148 |
1143 if (isMainThread()) { | 1149 if (isMainThread()) { |
1144 double collectionRate = 0; | 1150 double collectionRate = 0; |
1145 if (Heap::objectSizeAtLastGC() > 0) | 1151 if (Heap::objectSizeAtLastGC() > 0) |
1146 collectionRate = 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSi
zeAtLastGC(); | 1152 collectionRate = 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSi
zeAtLastGC(); |
1147 TRACE_COUNTER1("blink_gc", "ThreadState::collectionRate", static_cast<in
t>(100 * collectionRate)); | 1153 TRACE_COUNTER1("blink_gc", "ThreadState::collectionRate", static_cast<in
t>(100 * collectionRate)); |
1148 | 1154 |
1149 // See the comment in estimatedLiveObjectSize() for what we're | |
1150 // calculating here. | |
1151 // | |
1152 // Heap::markedObjectSize() may be underestimated here if any other | 1155 // Heap::markedObjectSize() may be underestimated here if any other |
1153 // thread has not yet finished lazy sweeping. | 1156 // thread has not yet finished lazy sweeping. |
1154 if (Heap::persistentCountAtLastGC() > 0) { | 1157 Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize()); |
1155 Heap::setHeapSizePerPersistent((Heap::markedObjectSize() + Heap::par
titionAllocSizeAtLastGC()) / Heap::persistentCountAtLastGC()); | |
1156 } | |
1157 } | 1158 } |
1158 | 1159 |
1159 switch (gcState()) { | 1160 switch (gcState()) { |
1160 case Sweeping: | 1161 case Sweeping: |
1161 setGCState(NoGCScheduled); | 1162 setGCState(NoGCScheduled); |
1162 break; | 1163 break; |
1163 case SweepingAndPreciseGCScheduled: | 1164 case SweepingAndPreciseGCScheduled: |
1164 setGCState(PreciseGCScheduled); | 1165 setGCState(PreciseGCScheduled); |
1165 break; | 1166 break; |
1166 case SweepingAndIdleGCScheduled: | 1167 case SweepingAndIdleGCScheduled: |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1584 json->beginArray(it->key.ascii().data()); | 1585 json->beginArray(it->key.ascii().data()); |
1585 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1586 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
1586 json->pushInteger(it->value.ages[age]); | 1587 json->pushInteger(it->value.ages[age]); |
1587 json->endArray(); | 1588 json->endArray(); |
1588 } | 1589 } |
1589 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); | 1590 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); |
1590 } | 1591 } |
1591 #endif | 1592 #endif |
1592 | 1593 |
1593 } // namespace blink | 1594 } // namespace blink |
OLD | NEW |