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 |