| 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 24 matching lines...) Expand all Loading... |
| 35 #include "platform/TraceEvent.h" | 35 #include "platform/TraceEvent.h" |
| 36 #include "platform/heap/AddressSanitizer.h" | 36 #include "platform/heap/AddressSanitizer.h" |
| 37 #include "platform/heap/CallbackStack.h" | 37 #include "platform/heap/CallbackStack.h" |
| 38 #include "platform/heap/Handle.h" | 38 #include "platform/heap/Handle.h" |
| 39 #include "platform/heap/Heap.h" | 39 #include "platform/heap/Heap.h" |
| 40 #include "platform/heap/SafePoint.h" | 40 #include "platform/heap/SafePoint.h" |
| 41 #include "platform/scheduler/Scheduler.h" | 41 #include "platform/scheduler/Scheduler.h" |
| 42 #include "public/platform/Platform.h" | 42 #include "public/platform/Platform.h" |
| 43 #include "public/platform/WebThread.h" | 43 #include "public/platform/WebThread.h" |
| 44 #include "public/platform/WebTraceLocation.h" | 44 #include "public/platform/WebTraceLocation.h" |
| 45 #include "wtf/Partitions.h" |
| 45 #include "wtf/ThreadingPrimitives.h" | 46 #include "wtf/ThreadingPrimitives.h" |
| 46 #if ENABLE(GC_PROFILING) | 47 #if ENABLE(GC_PROFILING) |
| 47 #include "platform/TracedValue.h" | 48 #include "platform/TracedValue.h" |
| 48 #include "wtf/text/StringHash.h" | 49 #include "wtf/text/StringHash.h" |
| 49 #endif | 50 #endif |
| 50 | 51 |
| 51 #if OS(WIN) | 52 #if OS(WIN) |
| 52 #include <stddef.h> | 53 #include <stddef.h> |
| 53 #include <windows.h> | 54 #include <windows.h> |
| 54 #include <winnt.h> | 55 #include <winnt.h> |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 AtomicallyInitializedStaticReference(PersistentNode, anchor, new PersistentA
nchor); | 494 AtomicallyInitializedStaticReference(PersistentNode, anchor, new PersistentA
nchor); |
| 494 return anchor; | 495 return anchor; |
| 495 } | 496 } |
| 496 | 497 |
| 497 Mutex& ThreadState::globalRootsMutex() | 498 Mutex& ThreadState::globalRootsMutex() |
| 498 { | 499 { |
| 499 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); | 500 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); |
| 500 return mutex; | 501 return mutex; |
| 501 } | 502 } |
| 502 | 503 |
| 503 // FIXME: We should improve the GC heuristics. | 504 // TODO(haraken): We should improve the GC heuristics. |
| 504 // These heuristics affect performance significantly. | 505 // These heuristics affect performance significantly. |
| 505 bool ThreadState::shouldScheduleIdleGC() | 506 bool ThreadState::shouldScheduleIdleGC() |
| 506 { | 507 { |
| 507 if (gcState() != NoGCScheduled) | 508 if (gcState() != NoGCScheduled) |
| 508 return false; | 509 return false; |
| 509 #if ENABLE(OILPAN) | 510 #if ENABLE(OILPAN) |
| 510 // The estimated size is updated when the main thread finishes lazy | 511 // The estimated size is updated when the main thread finishes lazy |
| 511 // sweeping. If this thread reaches here before the main thread finishes | 512 // sweeping. If this thread reaches here before the main thread finishes |
| 512 // lazy sweeping, the thread will use the estimated size of the last GC. | 513 // lazy sweeping, the thread will use the estimated size of the last GC. |
| 513 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); | 514 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); |
| 514 // Schedule an idle GC if more than 512 KB has been allocated since | 515 // Schedule an idle GC if more than 1Mb has been allocated since |
| 515 // the last GC and the current memory usage (=allocated + estimated) | 516 // the last GC and the current memory usage (=allocated + estimated) |
| 516 // is >50% larger than the estimated live memory usage. | 517 // is >50% larger than the estimated live memory usage. |
| 517 size_t allocatedObjectSize = Heap::allocatedObjectSize(); | 518 size_t currentObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectS
ize(); |
| 518 return allocatedObjectSize >= 512 * 1024 && allocatedObjectSize > estimatedL
iveObjectSize / 2; | 519 return currentObjectSize >= 1024 * 1024 && currentObjectSize > estimatedLive
ObjectSize / 2; |
| 519 #else | 520 #else |
| 520 return false; | 521 return false; |
| 521 #endif | 522 #endif |
| 522 } | 523 } |
| 523 | 524 |
| 524 // FIXME: We should improve the GC heuristics. | 525 // TODO(haraken): We should improve the GC heuristics. |
| 525 // These heuristics affect performance significantly. | 526 // These heuristics affect performance significantly. |
| 526 bool ThreadState::shouldSchedulePreciseGC() | 527 bool ThreadState::shouldSchedulePreciseGC() |
| 527 { | 528 { |
| 528 if (gcState() != NoGCScheduled) | 529 if (gcState() != NoGCScheduled) |
| 529 return false; | 530 return false; |
| 530 #if ENABLE(OILPAN) | 531 #if ENABLE(OILPAN) |
| 531 return false; | 532 return false; |
| 532 #else | 533 #else |
| 533 // The estimated size is updated when the main thread finishes lazy | 534 // The estimated size is updated when the main thread finishes lazy |
| 534 // sweeping. If this thread reaches here before the main thread finishes | 535 // sweeping. If this thread reaches here before the main thread finishes |
| 535 // lazy sweeping, the thread will use the estimated size of the last GC. | 536 // lazy sweeping, the thread will use the estimated size of the last GC. |
| 536 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); | 537 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); |
| 537 // Schedule a precise GC if more than 512 KB has been allocated since | 538 // Schedule a precise GC if more than 1Mb has been allocated since |
| 538 // the last GC and the current memory usage (=allocated + estimated) | 539 // the last GC and the current memory usage (=allocated + estimated) |
| 539 // is >50% larger than the estimated live memory usage. | 540 // is >50% larger than the estimated live memory usage. |
| 540 size_t allocatedObjectSize = Heap::allocatedObjectSize(); | 541 size_t currentObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectS
ize(); |
| 541 return allocatedObjectSize >= 512 * 1024 && allocatedObjectSize > estimatedL
iveObjectSize / 2; | 542 return currentObjectSize >= 1024 * 1024 && currentObjectSize > estimatedLive
ObjectSize / 2; |
| 542 #endif | 543 #endif |
| 543 } | 544 } |
| 544 | 545 |
| 545 // FIXME: We should improve the GC heuristics. | 546 // TODO(haraken): We should improve the GC heuristics. |
| 546 // These heuristics affect performance significantly. | 547 // These heuristics affect performance significantly. |
| 547 bool ThreadState::shouldForceConservativeGC() | 548 bool ThreadState::shouldForceConservativeGC() |
| 548 { | 549 { |
| 549 if (UNLIKELY(m_gcForbiddenCount)) | 550 if (UNLIKELY(m_gcForbiddenCount)) |
| 550 return false; | 551 return false; |
| 551 | 552 |
| 552 if (Heap::isUrgentGCRequested()) | |
| 553 return true; | |
| 554 | |
| 555 // The estimated size is updated when the main thread finishes lazy | 553 // The estimated size is updated when the main thread finishes lazy |
| 556 // sweeping. If this thread reaches here before the main thread finishes | 554 // sweeping. If this thread reaches here before the main thread finishes |
| 557 // lazy sweeping, the thread will use the estimated size of the last GC. | 555 // lazy sweeping, the thread will use the estimated size of the last GC. |
| 558 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); | 556 size_t estimatedLiveObjectSize = Heap::estimatedLiveObjectSize(); |
| 559 size_t allocatedObjectSize = Heap::allocatedObjectSize(); | 557 size_t allocatedObjectSize = Heap::allocatedObjectSize(); |
| 560 if (Heap::markedObjectSize() + allocatedObjectSize >= 300 * 1024 * 1024) { | 558 // Heap::markedObjectSize() may be underestimated if any thread has not |
| 559 // finished completeSweep(). |
| 560 size_t currentObjectSize = allocatedObjectSize + Heap::markedObjectSize() +
WTF::Partitions::totalSizeOfCommittedPages(); |
| 561 if (currentObjectSize >= 300 * 1024 * 1024) { |
| 561 // If we're consuming too much memory, trigger a conservative GC | 562 // If we're consuming too much memory, trigger a conservative GC |
| 562 // aggressively. This is a safe guard to avoid OOM. | 563 // aggressively. This is a safe guard to avoid OOM. |
| 563 return allocatedObjectSize > estimatedLiveObjectSize / 2; | 564 return allocatedObjectSize > estimatedLiveObjectSize / 2; |
| 564 } | 565 } |
| 565 // Schedule a conservative GC if more than 32 MB has been allocated since | 566 // Schedule a conservative GC if more than 32 MB has been allocated since |
| 566 // the last GC and the current memory usage (=allocated + estimated) | 567 // the last GC and the current memory usage (=allocated + estimated) |
| 567 // is >500% larger than the estimated live memory usage. | 568 // is >500% larger than the estimated live memory usage. |
| 568 return allocatedObjectSize >= 32 * 1024 * 1024 && allocatedObjectSize > 4 *
estimatedLiveObjectSize; | 569 return allocatedObjectSize >= 32 * 1024 * 1024 && allocatedObjectSize > 4 *
estimatedLiveObjectSize; |
| 569 } | 570 } |
| 570 | 571 |
| 571 void ThreadState::scheduleGCIfNeeded() | 572 void ThreadState::scheduleGCIfNeeded() |
| 572 { | 573 { |
| 573 checkThread(); | 574 checkThread(); |
| 574 // Allocation is allowed during sweeping, but those allocations should not | 575 // Allocation is allowed during sweeping, but those allocations should not |
| 575 // trigger nested GCs. Does not apply if an urgent GC has been requested. | 576 // trigger nested GCs. |
| 576 if (isSweepingInProgress() && UNLIKELY(!Heap::isUrgentGCRequested())) | 577 if (isSweepingInProgress()) |
| 577 return; | 578 return; |
| 578 ASSERT(!sweepForbidden()); | 579 ASSERT(!sweepForbidden()); |
| 579 | 580 |
| 580 if (shouldForceConservativeGC()) { | 581 if (shouldForceConservativeGC()) { |
| 581 if (Heap::isUrgentGCRequested()) { | 582 Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::Conserva
tiveGC); |
| 582 // If GC is deemed urgent, eagerly sweep and finalize any external a
llocations right away. | |
| 583 Heap::collectGarbage(HeapPointersOnStack, GCWithSweep, Heap::Conserv
ativeGC); | |
| 584 } else { | |
| 585 // Otherwise, schedule a lazy sweeping in an idle task. | |
| 586 Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::Cons
ervativeGC); | |
| 587 } | |
| 588 return; | 583 return; |
| 589 } | 584 } |
| 590 if (shouldSchedulePreciseGC()) | 585 if (shouldSchedulePreciseGC()) |
| 591 schedulePreciseGC(); | 586 schedulePreciseGC(); |
| 592 else if (shouldScheduleIdleGC()) | 587 else if (shouldScheduleIdleGC()) |
| 593 scheduleIdleGC(); | 588 scheduleIdleGC(); |
| 594 } | 589 } |
| 595 | 590 |
| 596 void ThreadState::performIdleGC(double deadlineSeconds) | 591 void ThreadState::performIdleGC(double deadlineSeconds) |
| 597 { | 592 { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 | 834 |
| 840 if (isMainThread()) | 835 if (isMainThread()) |
| 841 ScriptForbiddenScope::exit(); | 836 ScriptForbiddenScope::exit(); |
| 842 } | 837 } |
| 843 | 838 |
| 844 postSweep(); | 839 postSweep(); |
| 845 } | 840 } |
| 846 | 841 |
| 847 void ThreadState::postSweep() | 842 void ThreadState::postSweep() |
| 848 { | 843 { |
| 849 if (isMainThread()) | 844 if (isMainThread()) { |
| 845 // At the point where the main thread finishes lazy sweeping, |
| 846 // we estimate the live object size. Heap::markedObjectSize() |
| 847 // may be underestimated if any other thread has not finished |
| 848 // lazy sweeping. |
| 850 Heap::setEstimatedLiveObjectSize(Heap::markedObjectSize()); | 849 Heap::setEstimatedLiveObjectSize(Heap::markedObjectSize()); |
| 850 } |
| 851 | 851 |
| 852 switch (gcState()) { | 852 switch (gcState()) { |
| 853 case Sweeping: | 853 case Sweeping: |
| 854 setGCState(NoGCScheduled); | 854 setGCState(NoGCScheduled); |
| 855 break; | 855 break; |
| 856 case SweepingAndPreciseGCScheduled: | 856 case SweepingAndPreciseGCScheduled: |
| 857 setGCState(PreciseGCScheduled); | 857 setGCState(PreciseGCScheduled); |
| 858 break; | 858 break; |
| 859 case SweepingAndIdleGCScheduled: | 859 case SweepingAndIdleGCScheduled: |
| 860 setGCState(NoGCScheduled); | 860 setGCState(NoGCScheduled); |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 json->beginArray(it->key.ascii().data()); | 1292 json->beginArray(it->key.ascii().data()); |
| 1293 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1293 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
| 1294 json->pushInteger(it->value.ages[age]); | 1294 json->pushInteger(it->value.ages[age]); |
| 1295 json->endArray(); | 1295 json->endArray(); |
| 1296 } | 1296 } |
| 1297 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); | 1297 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); |
| 1298 } | 1298 } |
| 1299 #endif | 1299 #endif |
| 1300 | 1300 |
| 1301 } // namespace blink | 1301 } // namespace blink |
| OLD | NEW |