| 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 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 { | 562 { |
| 563 if (m_persistentAllocated >= m_persistentFreed) | 563 if (m_persistentAllocated >= m_persistentFreed) |
| 564 Heap::increasePersistentCount(m_persistentAllocated - m_persistentFreed)
; | 564 Heap::increasePersistentCount(m_persistentAllocated - m_persistentFreed)
; |
| 565 else | 565 else |
| 566 Heap::decreasePersistentCount(m_persistentFreed - m_persistentAllocated)
; | 566 Heap::decreasePersistentCount(m_persistentFreed - m_persistentAllocated)
; |
| 567 Heap::increaseCollectedPersistentCount(m_persistentFreed); | 567 Heap::increaseCollectedPersistentCount(m_persistentFreed); |
| 568 m_persistentAllocated = 0; | 568 m_persistentAllocated = 0; |
| 569 m_persistentFreed = 0; | 569 m_persistentFreed = 0; |
| 570 } | 570 } |
| 571 | 571 |
| 572 size_t ThreadState::currentObjectSize() |
| 573 { |
| 574 return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partiti
ons::totalSizeOfCommittedPages(); |
| 575 } |
| 576 |
| 572 size_t ThreadState::estimatedLiveObjectSize() | 577 size_t ThreadState::estimatedLiveObjectSize() |
| 573 { | 578 { |
| 574 // We estimate the live object size with the following equations. | 579 // We estimate the live object size with the following equations. |
| 575 // | 580 // |
| 576 // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persist
entCount(t0) | 581 // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persist
entCount(t0) |
| 577 // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionA
lloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) | 582 // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionA
lloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) |
| 578 // | 583 // |
| 579 // t0: The time when the last collectGarbage runs. | 584 // t0: The time when the last collectGarbage runs. |
| 580 // t1: The time when the last completeSweep runs. | 585 // t1: The time when the last completeSweep runs. |
| 581 // t: The current time. | 586 // t: The current time. |
| 582 // marked(t0, t): The size of marked objects between t0 and t. | 587 // marked(t0, t): The size of marked objects between t0 and t. |
| 583 // allocated(t0, t): The size of newly allocated objects between t0 and t. | 588 // allocated(t0, t): The size of newly allocated objects between t0 and t. |
| 584 // persistentCount(t): The number of existing persistent handles at t. | 589 // persistentCount(t): The number of existing persistent handles at t. |
| 585 // collectedPersistentCount(t0, t): | 590 // collectedPersistentCount(t0, t): |
| 586 // The number of persistent handles collected between | 591 // The number of persistent handles collected between |
| 587 // t0 and t. | 592 // t0 and t. |
| 588 // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t. | 593 // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t. |
| 589 size_t currentHeapSize = currentObjectSize(); | 594 size_t currentHeapSize = currentObjectSize(); |
| 590 size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent(
) * Heap::collectedPersistentCount(); | 595 size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent(
) * Heap::collectedPersistentCount(); |
| 591 size_t estimatedSize = 0; | 596 size_t estimatedSize = 0; |
| 592 if (currentHeapSize > heapSizeRetainedByCollectedPersistents) | 597 if (currentHeapSize > heapSizeRetainedByCollectedPersistents) |
| 593 estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents
; | 598 estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents
; |
| 594 TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(curren
tHeapSize / 1024, static_cast<size_t>(INT_MAX))); | |
| 595 TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::mi
n(estimatedSize / 1024, static_cast<size_t>(INT_MAX))); | |
| 596 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(
100.0 * currentHeapSize / estimatedSize)); | |
| 597 return estimatedSize; | 599 return estimatedSize; |
| 598 } | 600 } |
| 599 | 601 |
| 600 size_t ThreadState::currentObjectSize() | 602 double ThreadState::heapGrowingRate() |
| 601 { | 603 { |
| 602 return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partiti
ons::totalSizeOfCommittedPages(); | 604 size_t currentSize = currentObjectSize(); |
| 605 size_t estimatedSize = estimatedLiveObjectSize(); |
| 606 double growingRate = 1.0 * currentSize / estimatedSize; |
| 607 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))); |
| 609 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(
100 * growingRate)); |
| 610 return growingRate; |
| 611 } |
| 612 |
| 613 // TODO(haraken): We should improve the GC heuristics. |
| 614 // The heuristics affect performance significantly. |
| 615 bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double h
eapGrowingRateThreshold) |
| 616 { |
| 617 // If the allocated object size is small enough, don't trigger a GC. |
| 618 if (Heap::allocatedObjectSize() < allocatedObjectSizeThreshold) |
| 619 return false; |
| 620 // If the heap growing rate is large enough, trigger a GC. |
| 621 return heapGrowingRate() >= heapGrowingRateThreshold; |
| 603 } | 622 } |
| 604 | 623 |
| 605 bool ThreadState::shouldForceMemoryPressureGC() | 624 bool ThreadState::shouldForceMemoryPressureGC() |
| 606 { | 625 { |
| 607 // Avoid potential overflow by truncating to Kb. | 626 if (currentObjectSize() < 300 * 1024 * 1024) |
| 608 size_t currentObjectSizeKb = currentObjectSize() >> 10; | |
| 609 if (currentObjectSizeKb < 300 * 1024) | |
| 610 return false; | 627 return false; |
| 611 | 628 |
| 612 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; | |
| 613 // If we're consuming too much memory, trigger a conservative GC | 629 // If we're consuming too much memory, trigger a conservative GC |
| 614 // aggressively. This is a safe guard to avoid OOM. | 630 // aggressively. This is a safe guard to avoid OOM. |
| 615 return currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2; | 631 return judgeGCThreshold(0, 1.5); |
| 616 } | 632 } |
| 617 | 633 |
| 618 // TODO(haraken): We should improve the GC heuristics. | |
| 619 // These heuristics affect performance significantly. | |
| 620 bool ThreadState::shouldScheduleIdleGC() | 634 bool ThreadState::shouldScheduleIdleGC() |
| 621 { | 635 { |
| 622 if (gcState() != NoGCScheduled) | 636 if (gcState() != NoGCScheduled) |
| 623 return false; | 637 return false; |
| 624 #if ENABLE(IDLE_GC) | 638 #if ENABLE(IDLE_GC) |
| 625 // Avoid potential overflow by truncating to Kb. | 639 return judgeGCThreshold(1024 * 1024, 1.5); |
| 626 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; | |
| 627 // The estimated size is updated when the main thread finishes lazy | |
| 628 // sweeping. If this thread reaches here before the main thread finishes | |
| 629 // lazy sweeping, the thread will use the estimated size of the last GC. | |
| 630 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; | |
| 631 // Heap::markedObjectSize() may be underestimated if any thread has not | |
| 632 // finished completeSweep(). | |
| 633 size_t currentObjectSizeKb = currentObjectSize() >> 10; | |
| 634 // Schedule an idle GC if Oilpan has allocated more than 1 MB since | |
| 635 // the last GC and the current memory usage is >50% larger than | |
| 636 // the estimated live memory usage. | |
| 637 return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLive
ObjectSizeKb * 3) / 2; | |
| 638 #else | 640 #else |
| 639 return false; | 641 return false; |
| 640 #endif | 642 #endif |
| 641 } | 643 } |
| 642 | 644 |
| 643 // TODO(haraken): We should improve the GC heuristics. | |
| 644 // These heuristics affect performance significantly. | |
| 645 bool ThreadState::shouldSchedulePreciseGC() | 645 bool ThreadState::shouldSchedulePreciseGC() |
| 646 { | 646 { |
| 647 if (gcState() != NoGCScheduled) | 647 if (gcState() != NoGCScheduled) |
| 648 return false; | 648 return false; |
| 649 #if ENABLE(IDLE_GC) | 649 #if ENABLE(IDLE_GC) |
| 650 return false; | 650 return false; |
| 651 #else | 651 #else |
| 652 // Avoid potential overflow by truncating to Kb. | 652 return judgeGCThreshold(1024 * 1024, 1.5); |
| 653 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; | |
| 654 // The estimated size is updated when the main thread finishes lazy | |
| 655 // sweeping. If this thread reaches here before the main thread finishes | |
| 656 // lazy sweeping, the thread will use the estimated size of the last GC. | |
| 657 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; | |
| 658 // Heap::markedObjectSize() may be underestimated if any thread has not | |
| 659 // finished completeSweep(). | |
| 660 size_t currentObjectSizeKb = currentObjectSize() >> 10; | |
| 661 // Schedule a precise GC if Oilpan has allocated more than 1 MB since | |
| 662 // the last GC and the current memory usage is >50% larger than | |
| 663 // the estimated live memory usage. | |
| 664 return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLive
ObjectSizeKb * 3) / 2; | |
| 665 #endif | 653 #endif |
| 666 } | 654 } |
| 667 | 655 |
| 668 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio) | 656 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio) |
| 669 { | 657 { |
| 670 if (UNLIKELY(isGCForbidden())) | 658 if (UNLIKELY(isGCForbidden())) |
| 671 return false; | 659 return false; |
| 672 | 660 |
| 673 if (shouldForceMemoryPressureGC()) | 661 if (shouldForceMemoryPressureGC()) |
| 674 return true; | 662 return true; |
| 675 | 663 |
| 676 // Avoid potential overflow by truncating to Kb. | 664 return judgeGCThreshold(1024 * 1024, 1.5); |
| 677 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; | 665 } |
| 678 // The estimated size is updated when the main thread finishes lazy | 666 |
| 679 // sweeping. If this thread reaches here before the main thread finishes | 667 bool ThreadState::shouldForceConservativeGC() |
| 680 // lazy sweeping, the thread will use the estimated size of the last GC. | 668 { |
| 681 size_t estimatedLiveObjectSizeKb = (estimatedLiveObjectSize() >> 10) * (1 -
estimatedRemovalRatio); | 669 if (UNLIKELY(isGCForbidden())) |
| 682 // Heap::markedObjectSize() may be underestimated if any thread has not | 670 return false; |
| 683 // finished completeSweep(). | 671 |
| 684 size_t currentObjectSizeKb = currentObjectSize() >> 10; | 672 if (shouldForceMemoryPressureGC()) |
| 685 // Schedule a precise GC if Oilpan has allocated more than 1 MB since | 673 return true; |
| 686 // the last GC and the current memory usage is >50% larger than | 674 |
| 687 // the estimated live memory usage. | 675 // TODO(haraken): 400% is too large. Lower the heap growing factor. |
| 688 return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLive
ObjectSizeKb * 3) / 2; | 676 return judgeGCThreshold(32 * 1024 * 1024, 5.0); |
| 689 } | 677 } |
| 690 | 678 |
| 691 void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) | 679 void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) |
| 692 { | 680 { |
| 693 ASSERT(checkThread()); | 681 ASSERT(checkThread()); |
| 694 // Finish on-going lazy sweeping. | 682 // Finish on-going lazy sweeping. |
| 695 // TODO(haraken): It might not make sense to force completeSweep() for all | 683 // TODO(haraken): It might not make sense to force completeSweep() for all |
| 696 // page navigations. | 684 // page navigations. |
| 697 completeSweep(); | 685 completeSweep(); |
| 698 ASSERT(!isSweepingInProgress()); | 686 ASSERT(!isSweepingInProgress()); |
| 699 ASSERT(!sweepForbidden()); | 687 ASSERT(!sweepForbidden()); |
| 700 | 688 |
| 701 Heap::reportMemoryUsageForTracing(); | 689 Heap::reportMemoryUsageForTracing(); |
| 702 if (shouldSchedulePageNavigationGC(estimatedRemovalRatio)) | 690 if (shouldSchedulePageNavigationGC(estimatedRemovalRatio)) |
| 703 schedulePageNavigationGC(); | 691 schedulePageNavigationGC(); |
| 704 } | 692 } |
| 705 | 693 |
| 706 void ThreadState::schedulePageNavigationGC() | 694 void ThreadState::schedulePageNavigationGC() |
| 707 { | 695 { |
| 708 ASSERT(checkThread()); | 696 ASSERT(checkThread()); |
| 709 ASSERT(!isSweepingInProgress()); | 697 ASSERT(!isSweepingInProgress()); |
| 710 setGCState(PageNavigationGCScheduled); | 698 setGCState(PageNavigationGCScheduled); |
| 711 } | 699 } |
| 712 | 700 |
| 713 // TODO(haraken): We should improve the GC heuristics. | |
| 714 // These heuristics affect performance significantly. | |
| 715 bool ThreadState::shouldForceConservativeGC() | |
| 716 { | |
| 717 if (UNLIKELY(isGCForbidden())) | |
| 718 return false; | |
| 719 | |
| 720 if (shouldForceMemoryPressureGC()) | |
| 721 return true; | |
| 722 | |
| 723 // Avoid potential overflow by truncating to Kb. | |
| 724 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10; | |
| 725 // The estimated size is updated when the main thread finishes lazy | |
| 726 // sweeping. If this thread reaches here before the main thread finishes | |
| 727 // lazy sweeping, the thread will use the estimated size of the last GC. | |
| 728 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10; | |
| 729 // Heap::markedObjectSize() may be underestimated if any thread has not | |
| 730 // finished completeSweep(). | |
| 731 size_t currentObjectSizeKb = currentObjectSize() >> 10; | |
| 732 // Schedule a conservative GC if Oilpan has allocated more than 32 MB since | |
| 733 // the last GC and the current memory usage is >400% larger than | |
| 734 // the estimated live memory usage. | |
| 735 // TODO(haraken): 400% is too large. Lower the heap growing factor. | |
| 736 return allocatedObjectSizeKb >= 32 * 1024 && currentObjectSizeKb > 5 * estim
atedLiveObjectSizeKb; | |
| 737 } | |
| 738 | |
| 739 void ThreadState::scheduleGCIfNeeded() | 701 void ThreadState::scheduleGCIfNeeded() |
| 740 { | 702 { |
| 741 ASSERT(checkThread()); | 703 ASSERT(checkThread()); |
| 742 // Allocation is allowed during sweeping, but those allocations should not | 704 // Allocation is allowed during sweeping, but those allocations should not |
| 743 // trigger nested GCs. | 705 // trigger nested GCs. |
| 744 if (isSweepingInProgress()) | 706 if (isSweepingInProgress()) |
| 745 return; | 707 return; |
| 746 ASSERT(!sweepForbidden()); | 708 ASSERT(!sweepForbidden()); |
| 747 | 709 |
| 748 Heap::reportMemoryUsageForTracing(); | 710 Heap::reportMemoryUsageForTracing(); |
| (...skipping 883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1632 json->beginArray(it->key.ascii().data()); | 1594 json->beginArray(it->key.ascii().data()); |
| 1633 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1595 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
| 1634 json->pushInteger(it->value.ages[age]); | 1596 json->pushInteger(it->value.ages[age]); |
| 1635 json->endArray(); | 1597 json->endArray(); |
| 1636 } | 1598 } |
| 1637 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); | 1599 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); |
| 1638 } | 1600 } |
| 1639 #endif | 1601 #endif |
| 1640 | 1602 |
| 1641 } // namespace blink | 1603 } // namespace blink |
| OLD | NEW |