| 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 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 state->preGC(); | 462 state->preGC(); |
| 463 } | 463 } |
| 464 | 464 |
| 465 void ThreadHeap::postGC(BlinkGC::GCType gcType) | 465 void ThreadHeap::postGC(BlinkGC::GCType gcType) |
| 466 { | 466 { |
| 467 ASSERT(ThreadState::current()->isInGC()); | 467 ASSERT(ThreadState::current()->isInGC()); |
| 468 for (ThreadState* state : m_threads) | 468 for (ThreadState* state : m_threads) |
| 469 state->postGC(gcType); | 469 state->postGC(gcType); |
| 470 } | 470 } |
| 471 | 471 |
| 472 const char* ThreadHeap::gcReasonString(BlinkGC::GCReason reason) | |
| 473 { | |
| 474 switch (reason) { | |
| 475 case BlinkGC::IdleGC: | |
| 476 return "IdleGC"; | |
| 477 case BlinkGC::PreciseGC: | |
| 478 return "PreciseGC"; | |
| 479 case BlinkGC::ConservativeGC: | |
| 480 return "ConservativeGC"; | |
| 481 case BlinkGC::ForcedGC: | |
| 482 return "ForcedGC"; | |
| 483 case BlinkGC::MemoryPressureGC: | |
| 484 return "MemoryPressureGC"; | |
| 485 case BlinkGC::PageNavigationGC: | |
| 486 return "PageNavigationGC"; | |
| 487 default: | |
| 488 ASSERT_NOT_REACHED(); | |
| 489 } | |
| 490 return "<Unknown>"; | |
| 491 } | |
| 492 | |
| 493 void ThreadHeap::collectGarbage(BlinkGC::StackState stackState, BlinkGC::GCType
gcType, BlinkGC::GCReason reason) | |
| 494 { | |
| 495 ASSERT(gcType != BlinkGC::ThreadTerminationGC); | |
| 496 | |
| 497 ThreadState* state = ThreadState::current(); | |
| 498 // Nested collectGarbage() invocations aren't supported. | |
| 499 RELEASE_ASSERT(!state->isGCForbidden()); | |
| 500 state->completeSweep(); | |
| 501 | |
| 502 std::unique_ptr<Visitor> visitor = Visitor::create(state, gcType); | |
| 503 | |
| 504 SafePointScope safePointScope(stackState, state); | |
| 505 | |
| 506 // Resume all parked threads upon leaving this scope. | |
| 507 ParkThreadsScope parkThreadsScope(state); | |
| 508 | |
| 509 // Try to park the other threads. If we're unable to, bail out of the GC. | |
| 510 if (!parkThreadsScope.parkThreads()) | |
| 511 return; | |
| 512 | |
| 513 ScriptForbiddenIfMainThreadScope scriptForbidden; | |
| 514 | |
| 515 TRACE_EVENT2("blink_gc,devtools.timeline", "BlinkGCMarking", | |
| 516 "lazySweeping", gcType == BlinkGC::GCWithoutSweep, | |
| 517 "gcReason", gcReasonString(reason)); | |
| 518 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink_gc", "BlinkGC"); | |
| 519 double startTime = WTF::currentTimeMS(); | |
| 520 | |
| 521 if (gcType == BlinkGC::TakeSnapshot) | |
| 522 BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC(); | |
| 523 | |
| 524 // Disallow allocation during garbage collection (but not during the | |
| 525 // finalization that happens when the visitorScope is torn down). | |
| 526 ThreadState::NoAllocationScope noAllocationScope(state); | |
| 527 | |
| 528 state->heap().commitCallbackStacks(); | |
| 529 state->heap().preGC(); | |
| 530 | |
| 531 StackFrameDepthScope stackDepthScope(&state->heap().stackFrameDepth()); | |
| 532 | |
| 533 size_t totalObjectSize = state->heap().heapStats().allocatedObjectSize() + s
tate->heap().heapStats().markedObjectSize(); | |
| 534 if (gcType != BlinkGC::TakeSnapshot) | |
| 535 state->heap().resetHeapCounters(); | |
| 536 | |
| 537 { | |
| 538 // Access to the CrossThreadPersistentRegion has to be prevented while | |
| 539 // marking and global weak processing is in progress. If not, threads | |
| 540 // not attached to Oilpan and participating in this GC are able | |
| 541 // to allocate & free PersistentNodes, something the marking phase isn't | |
| 542 // capable of handling. | |
| 543 CrossThreadPersistentRegion::LockScope persistentLock(ProcessHeap::cross
ThreadPersistentRegion()); | |
| 544 | |
| 545 // 1. Trace persistent roots. | |
| 546 state->heap().visitPersistentRoots(visitor.get()); | |
| 547 | |
| 548 // 2. Trace objects reachable from the stack. We do this independent of
the | |
| 549 // given stackState since other threads might have a different stack sta
te. | |
| 550 state->heap().visitStackRoots(visitor.get()); | |
| 551 | |
| 552 // 3. Transitive closure to trace objects including ephemerons. | |
| 553 state->heap().processMarkingStack(visitor.get()); | |
| 554 | |
| 555 state->heap().postMarkingProcessing(visitor.get()); | |
| 556 state->heap().globalWeakProcessing(visitor.get()); | |
| 557 } | |
| 558 | |
| 559 // Now we can delete all orphaned pages because there are no dangling | |
| 560 // pointers to the orphaned pages. (If we have such dangling pointers, | |
| 561 // we should have crashed during marking before getting here.) | |
| 562 state->heap().getOrphanedPagePool()->decommitOrphanedPages(); | |
| 563 | |
| 564 double markingTimeInMilliseconds = WTF::currentTimeMS() - startTime; | |
| 565 state->heap().heapStats().setEstimatedMarkingTimePerByte(totalObjectSize ? (
markingTimeInMilliseconds / 1000 / totalObjectSize) : 0); | |
| 566 | |
| 567 #if PRINT_HEAP_STATS | |
| 568 dataLogF("ThreadHeap::collectGarbage (gcReason=%s, lazySweeping=%d, time=%.1
lfms)\n", gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep, markingTime
InMilliseconds); | |
| 569 #endif | |
| 570 | |
| 571 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, markingTimeHistogram,
new CustomCountHistogram("BlinkGC.CollectGarbage", 0, 10 * 1000, 50)); | |
| 572 markingTimeHistogram.count(markingTimeInMilliseconds); | |
| 573 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalObjectSpaceHistog
ram, new CustomCountHistogram("BlinkGC.TotalObjectSpace", 0, 4 * 1024 * 1024, 50
)); | |
| 574 totalObjectSpaceHistogram.count(ProcessHeap::totalAllocatedObjectSize() / 10
24); | |
| 575 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalAllocatedSpaceHis
togram, new CustomCountHistogram("BlinkGC.TotalAllocatedSpace", 0, 4 * 1024 * 10
24, 50)); | |
| 576 totalAllocatedSpaceHistogram.count(ProcessHeap::totalAllocatedSpace() / 1024
); | |
| 577 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, gcReasonHistogram, new
EnumerationHistogram("BlinkGC.GCReason", BlinkGC::NumberOfGCReason)); | |
| 578 gcReasonHistogram.count(reason); | |
| 579 | |
| 580 state->heap().m_lastGCReason = reason; | |
| 581 | |
| 582 ThreadHeap::reportMemoryUsageHistogram(); | |
| 583 WTF::Partitions::reportMemoryUsageHistogram(); | |
| 584 | |
| 585 state->heap().postGC(gcType); | |
| 586 state->heap().decommitCallbackStacks(); | |
| 587 } | |
| 588 | |
| 589 void ThreadHeap::collectGarbageForTerminatingThread(ThreadState* state) | |
| 590 { | |
| 591 { | |
| 592 // A thread-specific termination GC must not allow other global GCs to g
o | |
| 593 // ahead while it is running, hence the termination GC does not enter a | |
| 594 // safepoint. VisitorScope will not enter also a safepoint scope for | |
| 595 // ThreadTerminationGC. | |
| 596 std::unique_ptr<Visitor> visitor = Visitor::create(state, BlinkGC::Threa
dTerminationGC); | |
| 597 | |
| 598 ThreadState::NoAllocationScope noAllocationScope(state); | |
| 599 | |
| 600 state->heap().commitCallbackStacks(); | |
| 601 state->preGC(); | |
| 602 | |
| 603 // 1. Trace the thread local persistent roots. For thread local GCs we | |
| 604 // don't trace the stack (ie. no conservative scanning) since this is | |
| 605 // only called during thread shutdown where there should be no objects | |
| 606 // on the stack. | |
| 607 // We also assume that orphaned pages have no objects reachable from | |
| 608 // persistent handles on other threads or CrossThreadPersistents. The | |
| 609 // only cases where this could happen is if a subsequent conservative | |
| 610 // global GC finds a "pointer" on the stack or due to a programming | |
| 611 // error where an object has a dangling cross-thread pointer to an | |
| 612 // object on this heap. | |
| 613 state->visitPersistents(visitor.get()); | |
| 614 | |
| 615 // 2. Trace objects reachable from the thread's persistent roots | |
| 616 // including ephemerons. | |
| 617 state->heap().processMarkingStack(visitor.get()); | |
| 618 | |
| 619 state->heap().postMarkingProcessing(visitor.get()); | |
| 620 state->heap().globalWeakProcessing(visitor.get()); | |
| 621 | |
| 622 state->postGC(BlinkGC::GCWithSweep); | |
| 623 state->heap().decommitCallbackStacks(); | |
| 624 } | |
| 625 state->preSweep(); | |
| 626 } | |
| 627 | |
| 628 void ThreadHeap::processMarkingStack(Visitor* visitor) | 472 void ThreadHeap::processMarkingStack(Visitor* visitor) |
| 629 { | 473 { |
| 630 // Ephemeron fixed point loop. | 474 // Ephemeron fixed point loop. |
| 631 do { | 475 do { |
| 632 { | 476 { |
| 633 // Iteratively mark all objects that are reachable from the objects | 477 // Iteratively mark all objects that are reachable from the objects |
| 634 // currently pushed onto the marking stack. | 478 // currently pushed onto the marking stack. |
| 635 TRACE_EVENT0("blink_gc", "ThreadHeap::processMarkingStackSingleThrea
ded"); | 479 TRACE_EVENT0("blink_gc", "ThreadHeap::processMarkingStackSingleThrea
ded"); |
| 636 while (popAndInvokeTraceCallback(visitor)) { } | 480 while (popAndInvokeTraceCallback(visitor)) { } |
| 637 } | 481 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 | 517 |
| 674 // It is not permitted to trace pointers of live objects in the weak | 518 // It is not permitted to trace pointers of live objects in the weak |
| 675 // callback phase, so the marking stack should still be empty here. | 519 // callback phase, so the marking stack should still be empty here. |
| 676 ASSERT(m_markingStack->isEmpty()); | 520 ASSERT(m_markingStack->isEmpty()); |
| 677 | 521 |
| 678 double timeForGlobalWeakProcessing = WTF::currentTimeMS() - startTime; | 522 double timeForGlobalWeakProcessing = WTF::currentTimeMS() - startTime; |
| 679 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, globalWeakTimeHistogra
m, new CustomCountHistogram("BlinkGC.TimeForGlobalWeakProcessing", 1, 10 * 1000,
50)); | 523 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, globalWeakTimeHistogra
m, new CustomCountHistogram("BlinkGC.TimeForGlobalWeakProcessing", 1, 10 * 1000,
50)); |
| 680 globalWeakTimeHistogram.count(timeForGlobalWeakProcessing); | 524 globalWeakTimeHistogram.count(timeForGlobalWeakProcessing); |
| 681 } | 525 } |
| 682 | 526 |
| 683 void ThreadHeap::collectAllGarbage() | |
| 684 { | |
| 685 // We need to run multiple GCs to collect a chain of persistent handles. | |
| 686 size_t previousLiveObjects = 0; | |
| 687 ThreadState* state = ThreadState::current(); | |
| 688 for (int i = 0; i < 5; ++i) { | |
| 689 collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Bli
nkGC::ForcedGC); | |
| 690 size_t liveObjects = state->heap().heapStats().markedObjectSize(); | |
| 691 if (liveObjects == previousLiveObjects) | |
| 692 break; | |
| 693 previousLiveObjects = liveObjects; | |
| 694 } | |
| 695 } | |
| 696 | |
| 697 void ThreadHeap::reportMemoryUsageHistogram() | 527 void ThreadHeap::reportMemoryUsageHistogram() |
| 698 { | 528 { |
| 699 static size_t supportedMaxSizeInMB = 4 * 1024; | 529 static size_t supportedMaxSizeInMB = 4 * 1024; |
| 700 static size_t observedMaxSizeInMB = 0; | 530 static size_t observedMaxSizeInMB = 0; |
| 701 | 531 |
| 702 // We only report the memory in the main thread. | 532 // We only report the memory in the main thread. |
| 703 if (!isMainThread()) | 533 if (!isMainThread()) |
| 704 return; | 534 return; |
| 705 // +1 is for rounding up the sizeInMB. | 535 // +1 is for rounding up the sizeInMB. |
| 706 size_t sizeInMB = ThreadState::current()->heap().heapStats().allocatedSpace(
) / 1024 / 1024 + 1; | 536 size_t sizeInMB = ThreadState::current()->heap().heapStats().allocatedSpace(
) / 1024 / 1024 + 1; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 ProcessHeap::decreaseTotalMarkedObjectSize(m_stats.markedObjectSize()); | 639 ProcessHeap::decreaseTotalMarkedObjectSize(m_stats.markedObjectSize()); |
| 810 | 640 |
| 811 m_stats.reset(); | 641 m_stats.reset(); |
| 812 for (ThreadState* state : m_threads) | 642 for (ThreadState* state : m_threads) |
| 813 state->resetHeapCounters(); | 643 state->resetHeapCounters(); |
| 814 } | 644 } |
| 815 | 645 |
| 816 ThreadHeap* ThreadHeap::s_mainThreadHeap = nullptr; | 646 ThreadHeap* ThreadHeap::s_mainThreadHeap = nullptr; |
| 817 | 647 |
| 818 } // namespace blink | 648 } // namespace blink |
| OLD | NEW |