| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 | 229 |
| 230 | 230 |
| 231 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { | 231 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { |
| 232 if (IntrusiveMarking::IsMarked(object)) { | 232 if (IntrusiveMarking::IsMarked(object)) { |
| 233 return IntrusiveMarking::SizeOfMarkedObject(object); | 233 return IntrusiveMarking::SizeOfMarkedObject(object); |
| 234 } | 234 } |
| 235 return object->SizeFromMap(object->map()); | 235 return object->SizeFromMap(object->map()); |
| 236 } | 236 } |
| 237 | 237 |
| 238 | 238 |
| 239 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { | 239 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, |
| 240 const char** reason) { |
| 240 // Is global GC requested? | 241 // Is global GC requested? |
| 241 if (space != NEW_SPACE || FLAG_gc_global) { | 242 if (space != NEW_SPACE || FLAG_gc_global) { |
| 242 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); | 243 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); |
| 244 *reason = "GC in old space requested"; |
| 243 return MARK_COMPACTOR; | 245 return MARK_COMPACTOR; |
| 244 } | 246 } |
| 245 | 247 |
| 246 // Is enough data promoted to justify a global GC? | 248 // Is enough data promoted to justify a global GC? |
| 247 if (OldGenerationPromotionLimitReached()) { | 249 if (OldGenerationPromotionLimitReached()) { |
| 248 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); | 250 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); |
| 251 *reason = "promotion limit reached"; |
| 249 return MARK_COMPACTOR; | 252 return MARK_COMPACTOR; |
| 250 } | 253 } |
| 251 | 254 |
| 252 // Have allocation in OLD and LO failed? | 255 // Have allocation in OLD and LO failed? |
| 253 if (old_gen_exhausted_) { | 256 if (old_gen_exhausted_) { |
| 254 isolate_->counters()-> | 257 isolate_->counters()-> |
| 255 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); | 258 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
| 259 *reason = "old generations exhausted"; |
| 256 return MARK_COMPACTOR; | 260 return MARK_COMPACTOR; |
| 257 } | 261 } |
| 258 | 262 |
| 259 // Is there enough space left in OLD to guarantee that a scavenge can | 263 // Is there enough space left in OLD to guarantee that a scavenge can |
| 260 // succeed? | 264 // succeed? |
| 261 // | 265 // |
| 262 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available | 266 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available |
| 263 // for object promotion. It counts only the bytes that the memory | 267 // for object promotion. It counts only the bytes that the memory |
| 264 // allocator has not yet allocated from the OS and assigned to any space, | 268 // allocator has not yet allocated from the OS and assigned to any space, |
| 265 // and does not count available bytes already in the old space or code | 269 // and does not count available bytes already in the old space or code |
| 266 // space. Undercounting is safe---we may get an unrequested full GC when | 270 // space. Undercounting is safe---we may get an unrequested full GC when |
| 267 // a scavenge would have succeeded. | 271 // a scavenge would have succeeded. |
| 268 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { | 272 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { |
| 269 isolate_->counters()-> | 273 isolate_->counters()-> |
| 270 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); | 274 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
| 275 *reason = "scavenge might not succeed"; |
| 271 return MARK_COMPACTOR; | 276 return MARK_COMPACTOR; |
| 272 } | 277 } |
| 273 | 278 |
| 274 // Default | 279 // Default |
| 280 *reason = NULL; |
| 275 return SCAVENGER; | 281 return SCAVENGER; |
| 276 } | 282 } |
| 277 | 283 |
| 278 | 284 |
| 279 // TODO(1238405): Combine the infrastructure for --heap-stats and | 285 // TODO(1238405): Combine the infrastructure for --heap-stats and |
| 280 // --log-gc to avoid the complicated preprocessor and flag testing. | 286 // --log-gc to avoid the complicated preprocessor and flag testing. |
| 281 void Heap::ReportStatisticsBeforeGC() { | 287 void Heap::ReportStatisticsBeforeGC() { |
| 282 // Heap::ReportHeapStatistics will also log NewSpace statistics when | 288 // Heap::ReportHeapStatistics will also log NewSpace statistics when |
| 283 // compiled --log-gc is set. The following logic is used to avoid | 289 // compiled --log-gc is set. The following logic is used to avoid |
| 284 // double logging. | 290 // double logging. |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 symbol_table()->NumberOfElements()); | 430 symbol_table()->NumberOfElements()); |
| 425 #if defined(DEBUG) | 431 #if defined(DEBUG) |
| 426 ReportStatisticsAfterGC(); | 432 ReportStatisticsAfterGC(); |
| 427 #endif // DEBUG | 433 #endif // DEBUG |
| 428 #ifdef ENABLE_DEBUGGER_SUPPORT | 434 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 429 isolate_->debug()->AfterGarbageCollection(); | 435 isolate_->debug()->AfterGarbageCollection(); |
| 430 #endif // ENABLE_DEBUGGER_SUPPORT | 436 #endif // ENABLE_DEBUGGER_SUPPORT |
| 431 } | 437 } |
| 432 | 438 |
| 433 | 439 |
| 434 void Heap::CollectAllGarbage(int flags) { | 440 void Heap::CollectAllGarbage(int flags, const char* gc_reason) { |
| 435 // Since we are ignoring the return value, the exact choice of space does | 441 // Since we are ignoring the return value, the exact choice of space does |
| 436 // not matter, so long as we do not specify NEW_SPACE, which would not | 442 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 437 // cause a full GC. | 443 // cause a full GC. |
| 438 mark_compact_collector_.SetFlags(flags); | 444 mark_compact_collector_.SetFlags(flags); |
| 439 CollectGarbage(OLD_POINTER_SPACE); | 445 CollectGarbage(OLD_POINTER_SPACE, gc_reason); |
| 440 mark_compact_collector_.SetFlags(kNoGCFlags); | 446 mark_compact_collector_.SetFlags(kNoGCFlags); |
| 441 } | 447 } |
| 442 | 448 |
| 443 | 449 |
| 444 void Heap::CollectAllAvailableGarbage() { | 450 void Heap::CollectAllAvailableGarbage(const char* gc_reason) { |
| 445 // Since we are ignoring the return value, the exact choice of space does | 451 // Since we are ignoring the return value, the exact choice of space does |
| 446 // not matter, so long as we do not specify NEW_SPACE, which would not | 452 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 447 // cause a full GC. | 453 // cause a full GC. |
| 448 // Major GC would invoke weak handle callbacks on weakly reachable | 454 // Major GC would invoke weak handle callbacks on weakly reachable |
| 449 // handles, but won't collect weakly reachable objects until next | 455 // handles, but won't collect weakly reachable objects until next |
| 450 // major GC. Therefore if we collect aggressively and weak handle callback | 456 // major GC. Therefore if we collect aggressively and weak handle callback |
| 451 // has been invoked, we rerun major GC to release objects which become | 457 // has been invoked, we rerun major GC to release objects which become |
| 452 // garbage. | 458 // garbage. |
| 453 // Note: as weak callbacks can execute arbitrary code, we cannot | 459 // Note: as weak callbacks can execute arbitrary code, we cannot |
| 454 // hope that eventually there will be no weak callbacks invocations. | 460 // hope that eventually there will be no weak callbacks invocations. |
| 455 // Therefore stop recollecting after several attempts. | 461 // Therefore stop recollecting after several attempts. |
| 456 mark_compact_collector()->SetFlags(kMakeHeapIterableMask); | 462 mark_compact_collector()->SetFlags(kMakeHeapIterableMask | |
| 463 kReduceMemoryFootprintMask); |
| 457 isolate_->compilation_cache()->Clear(); | 464 isolate_->compilation_cache()->Clear(); |
| 458 const int kMaxNumberOfAttempts = 7; | 465 const int kMaxNumberOfAttempts = 7; |
| 459 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { | 466 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { |
| 460 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { | 467 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) { |
| 461 break; | 468 break; |
| 462 } | 469 } |
| 463 } | 470 } |
| 464 mark_compact_collector()->SetFlags(kNoGCFlags); | 471 mark_compact_collector()->SetFlags(kNoGCFlags); |
| 465 new_space_.Shrink(); | 472 new_space_.Shrink(); |
| 466 UncommitFromSpace(); | 473 UncommitFromSpace(); |
| 467 Shrink(); | 474 Shrink(); |
| 468 incremental_marking()->UncommitMarkingDeque(); | 475 incremental_marking()->UncommitMarkingDeque(); |
| 469 } | 476 } |
| 470 | 477 |
| 471 | 478 |
| 472 bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { | 479 bool Heap::CollectGarbage(AllocationSpace space, |
| 480 GarbageCollector collector, |
| 481 const char* gc_reason, |
| 482 const char* collector_reason) { |
| 473 // The VM is in the GC state until exiting this function. | 483 // The VM is in the GC state until exiting this function. |
| 474 VMState state(isolate_, GC); | 484 VMState state(isolate_, GC); |
| 475 | 485 |
| 476 #ifdef DEBUG | 486 #ifdef DEBUG |
| 477 // Reset the allocation timeout to the GC interval, but make sure to | 487 // Reset the allocation timeout to the GC interval, but make sure to |
| 478 // allow at least a few allocations after a collection. The reason | 488 // allow at least a few allocations after a collection. The reason |
| 479 // for this is that we have a lot of allocation sequences and we | 489 // for this is that we have a lot of allocation sequences and we |
| 480 // assume that a garbage collection will allow the subsequent | 490 // assume that a garbage collection will allow the subsequent |
| 481 // allocation attempts to go through. | 491 // allocation attempts to go through. |
| 482 allocation_timeout_ = Max(6, FLAG_gc_interval); | 492 allocation_timeout_ = Max(6, FLAG_gc_interval); |
| 483 #endif | 493 #endif |
| 484 | 494 |
| 485 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { | 495 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { |
| 486 if (FLAG_trace_incremental_marking) { | 496 if (FLAG_trace_incremental_marking) { |
| 487 PrintF("[IncrementalMarking] Scavenge during marking.\n"); | 497 PrintF("[IncrementalMarking] Scavenge during marking.\n"); |
| 488 } | 498 } |
| 489 } | 499 } |
| 490 | 500 |
| 491 if (collector == MARK_COMPACTOR && | 501 if (collector == MARK_COMPACTOR && |
| 492 !mark_compact_collector()->PreciseSweepingRequired() && | 502 !mark_compact_collector()->PreciseSweepingRequired() && |
| 493 !incremental_marking()->IsStopped() && | 503 !incremental_marking()->IsStopped() && |
| 494 !incremental_marking()->should_hurry() && | 504 !incremental_marking()->should_hurry() && |
| 495 FLAG_incremental_marking_steps) { | 505 FLAG_incremental_marking_steps) { |
| 496 if (FLAG_trace_incremental_marking) { | 506 if (FLAG_trace_incremental_marking) { |
| 497 PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); | 507 PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); |
| 498 } | 508 } |
| 499 collector = SCAVENGER; | 509 collector = SCAVENGER; |
| 510 collector_reason = "incremental marking delaying mark-sweep"; |
| 500 } | 511 } |
| 501 | 512 |
| 502 bool next_gc_likely_to_collect_more = false; | 513 bool next_gc_likely_to_collect_more = false; |
| 503 | 514 |
| 504 { GCTracer tracer(this); | 515 { GCTracer tracer(this, gc_reason, collector_reason); |
| 505 GarbageCollectionPrologue(); | 516 GarbageCollectionPrologue(); |
| 506 // The GC count was incremented in the prologue. Tell the tracer about | 517 // The GC count was incremented in the prologue. Tell the tracer about |
| 507 // it. | 518 // it. |
| 508 tracer.set_gc_count(gc_count_); | 519 tracer.set_gc_count(gc_count_); |
| 509 | 520 |
| 510 // Tell the tracer which collector we've selected. | 521 // Tell the tracer which collector we've selected. |
| 511 tracer.set_collector(collector); | 522 tracer.set_collector(collector); |
| 512 | 523 |
| 513 HistogramTimer* rate = (collector == SCAVENGER) | 524 HistogramTimer* rate = (collector == SCAVENGER) |
| 514 ? isolate_->counters()->gc_scavenger() | 525 ? isolate_->counters()->gc_scavenger() |
| (...skipping 11 matching lines...) Expand all Loading... |
| 526 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { | 537 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) { |
| 527 incremental_marking()->Start(); | 538 incremental_marking()->Start(); |
| 528 } | 539 } |
| 529 } | 540 } |
| 530 | 541 |
| 531 return next_gc_likely_to_collect_more; | 542 return next_gc_likely_to_collect_more; |
| 532 } | 543 } |
| 533 | 544 |
| 534 | 545 |
| 535 void Heap::PerformScavenge() { | 546 void Heap::PerformScavenge() { |
| 536 GCTracer tracer(this); | 547 GCTracer tracer(this, NULL, NULL); |
| 537 if (incremental_marking()->IsStopped()) { | 548 if (incremental_marking()->IsStopped()) { |
| 538 PerformGarbageCollection(SCAVENGER, &tracer); | 549 PerformGarbageCollection(SCAVENGER, &tracer); |
| 539 } else { | 550 } else { |
| 540 PerformGarbageCollection(MARK_COMPACTOR, &tracer); | 551 PerformGarbageCollection(MARK_COMPACTOR, &tracer); |
| 541 } | 552 } |
| 542 } | 553 } |
| 543 | 554 |
| 544 | 555 |
| 545 #ifdef DEBUG | 556 #ifdef DEBUG |
| 546 // Helper class for verifying the symbol table. | 557 // Helper class for verifying the symbol table. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 PagedSpace* code_space = Heap::code_space(); | 592 PagedSpace* code_space = Heap::code_space(); |
| 582 PagedSpace* map_space = Heap::map_space(); | 593 PagedSpace* map_space = Heap::map_space(); |
| 583 PagedSpace* cell_space = Heap::cell_space(); | 594 PagedSpace* cell_space = Heap::cell_space(); |
| 584 LargeObjectSpace* lo_space = Heap::lo_space(); | 595 LargeObjectSpace* lo_space = Heap::lo_space(); |
| 585 bool gc_performed = true; | 596 bool gc_performed = true; |
| 586 int counter = 0; | 597 int counter = 0; |
| 587 static const int kThreshold = 20; | 598 static const int kThreshold = 20; |
| 588 while (gc_performed && counter++ < kThreshold) { | 599 while (gc_performed && counter++ < kThreshold) { |
| 589 gc_performed = false; | 600 gc_performed = false; |
| 590 if (!new_space->ReserveSpace(new_space_size)) { | 601 if (!new_space->ReserveSpace(new_space_size)) { |
| 591 Heap::CollectGarbage(NEW_SPACE); | 602 Heap::CollectGarbage(NEW_SPACE, |
| 603 "failed to reserve space in the new space"); |
| 592 gc_performed = true; | 604 gc_performed = true; |
| 593 } | 605 } |
| 594 if (!old_pointer_space->ReserveSpace(pointer_space_size)) { | 606 if (!old_pointer_space->ReserveSpace(pointer_space_size)) { |
| 595 Heap::CollectGarbage(OLD_POINTER_SPACE); | 607 Heap::CollectGarbage(OLD_POINTER_SPACE, |
| 608 "failed to reserve space in the old pointer space"); |
| 596 gc_performed = true; | 609 gc_performed = true; |
| 597 } | 610 } |
| 598 if (!(old_data_space->ReserveSpace(data_space_size))) { | 611 if (!(old_data_space->ReserveSpace(data_space_size))) { |
| 599 Heap::CollectGarbage(OLD_DATA_SPACE); | 612 Heap::CollectGarbage(OLD_DATA_SPACE, |
| 613 "failed to reserve space in the old data space"); |
| 600 gc_performed = true; | 614 gc_performed = true; |
| 601 } | 615 } |
| 602 if (!(code_space->ReserveSpace(code_space_size))) { | 616 if (!(code_space->ReserveSpace(code_space_size))) { |
| 603 Heap::CollectGarbage(CODE_SPACE); | 617 Heap::CollectGarbage(CODE_SPACE, |
| 618 "failed to reserve space in the code space"); |
| 604 gc_performed = true; | 619 gc_performed = true; |
| 605 } | 620 } |
| 606 if (!(map_space->ReserveSpace(map_space_size))) { | 621 if (!(map_space->ReserveSpace(map_space_size))) { |
| 607 Heap::CollectGarbage(MAP_SPACE); | 622 Heap::CollectGarbage(MAP_SPACE, |
| 623 "failed to reserve space in the map space"); |
| 608 gc_performed = true; | 624 gc_performed = true; |
| 609 } | 625 } |
| 610 if (!(cell_space->ReserveSpace(cell_space_size))) { | 626 if (!(cell_space->ReserveSpace(cell_space_size))) { |
| 611 Heap::CollectGarbage(CELL_SPACE); | 627 Heap::CollectGarbage(CELL_SPACE, |
| 628 "failed to reserve space in the cell space"); |
| 612 gc_performed = true; | 629 gc_performed = true; |
| 613 } | 630 } |
| 614 // We add a slack-factor of 2 in order to have space for a series of | 631 // We add a slack-factor of 2 in order to have space for a series of |
| 615 // large-object allocations that are only just larger than the page size. | 632 // large-object allocations that are only just larger than the page size. |
| 616 large_object_size *= 2; | 633 large_object_size *= 2; |
| 617 // The ReserveSpace method on the large object space checks how much | 634 // The ReserveSpace method on the large object space checks how much |
| 618 // we can expand the old generation. This includes expansion caused by | 635 // we can expand the old generation. This includes expansion caused by |
| 619 // allocation in the other spaces. | 636 // allocation in the other spaces. |
| 620 large_object_size += cell_space_size + map_space_size + code_space_size + | 637 large_object_size += cell_space_size + map_space_size + code_space_size + |
| 621 data_space_size + pointer_space_size; | 638 data_space_size + pointer_space_size; |
| 622 if (!(lo_space->ReserveSpace(large_object_size))) { | 639 if (!(lo_space->ReserveSpace(large_object_size))) { |
| 623 Heap::CollectGarbage(LO_SPACE); | 640 Heap::CollectGarbage(LO_SPACE, |
| 641 "failed to reserve space in the large object space"); |
| 624 gc_performed = true; | 642 gc_performed = true; |
| 625 } | 643 } |
| 626 } | 644 } |
| 627 | 645 |
| 628 if (gc_performed) { | 646 if (gc_performed) { |
| 629 // Failed to reserve the space after several attempts. | 647 // Failed to reserve the space after several attempts. |
| 630 V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); | 648 V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); |
| 631 } | 649 } |
| 632 } | 650 } |
| 633 | 651 |
| (...skipping 4101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4735 | 4753 |
| 4736 bool Heap::IsHeapIterable() { | 4754 bool Heap::IsHeapIterable() { |
| 4737 return (!old_pointer_space()->was_swept_conservatively() && | 4755 return (!old_pointer_space()->was_swept_conservatively() && |
| 4738 !old_data_space()->was_swept_conservatively()); | 4756 !old_data_space()->was_swept_conservatively()); |
| 4739 } | 4757 } |
| 4740 | 4758 |
| 4741 | 4759 |
| 4742 void Heap::EnsureHeapIsIterable() { | 4760 void Heap::EnsureHeapIsIterable() { |
| 4743 ASSERT(IsAllocationAllowed()); | 4761 ASSERT(IsAllocationAllowed()); |
| 4744 if (!IsHeapIterable()) { | 4762 if (!IsHeapIterable()) { |
| 4745 CollectAllGarbage(kMakeHeapIterableMask); | 4763 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); |
| 4746 } | 4764 } |
| 4747 ASSERT(IsHeapIterable()); | 4765 ASSERT(IsHeapIterable()); |
| 4748 } | 4766 } |
| 4749 | 4767 |
| 4750 | 4768 |
| 4751 bool Heap::IdleNotification(int hint) { | 4769 bool Heap::IdleNotification(int hint) { |
| 4752 if (hint >= 1000) return IdleGlobalGC(); | 4770 if (hint >= 1000) return IdleGlobalGC(); |
| 4753 if (contexts_disposed_ > 0 || !FLAG_incremental_marking || | 4771 if (contexts_disposed_ > 0 || !FLAG_incremental_marking || |
| 4754 FLAG_expose_gc || Serializer::enabled()) { | 4772 FLAG_expose_gc || Serializer::enabled()) { |
| 4755 return true; | 4773 return true; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4805 incremental_marking()->Step(step_size); | 4823 incremental_marking()->Step(step_size); |
| 4806 idle_notification_will_schedule_next_gc_ = false; | 4824 idle_notification_will_schedule_next_gc_ = false; |
| 4807 | 4825 |
| 4808 if (incremental_marking()->IsComplete()) { | 4826 if (incremental_marking()->IsComplete()) { |
| 4809 bool uncommit = false; | 4827 bool uncommit = false; |
| 4810 if (gc_count_at_last_idle_gc_ == gc_count_) { | 4828 if (gc_count_at_last_idle_gc_ == gc_count_) { |
| 4811 // No GC since the last full GC, the mutator is probably not active. | 4829 // No GC since the last full GC, the mutator is probably not active. |
| 4812 isolate_->compilation_cache()->Clear(); | 4830 isolate_->compilation_cache()->Clear(); |
| 4813 uncommit = true; | 4831 uncommit = true; |
| 4814 } | 4832 } |
| 4815 CollectAllGarbage(kNoGCFlags); | 4833 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); |
| 4816 gc_count_at_last_idle_gc_ = gc_count_; | 4834 gc_count_at_last_idle_gc_ = gc_count_; |
| 4817 if (uncommit) { | 4835 if (uncommit) { |
| 4818 new_space_.Shrink(); | 4836 new_space_.Shrink(); |
| 4819 UncommitFromSpace(); | 4837 UncommitFromSpace(); |
| 4820 } | 4838 } |
| 4821 } | 4839 } |
| 4822 return false; | 4840 return false; |
| 4823 } | 4841 } |
| 4824 | 4842 |
| 4825 | 4843 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4846 number_idle_notifications_ = | 4864 number_idle_notifications_ = |
| 4847 Min(number_idle_notifications_ + 1, kMaxIdleCount); | 4865 Min(number_idle_notifications_ + 1, kMaxIdleCount); |
| 4848 } else { | 4866 } else { |
| 4849 number_idle_notifications_ = 0; | 4867 number_idle_notifications_ = 0; |
| 4850 last_idle_notification_gc_count_ = gc_count_; | 4868 last_idle_notification_gc_count_ = gc_count_; |
| 4851 } | 4869 } |
| 4852 | 4870 |
| 4853 if (number_idle_notifications_ == kIdlesBeforeScavenge) { | 4871 if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
| 4854 if (contexts_disposed_ > 0) { | 4872 if (contexts_disposed_ > 0) { |
| 4855 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4873 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4856 CollectAllGarbage(kNoGCFlags); | 4874 CollectAllGarbage(kReduceMemoryFootprintMask, |
| 4875 "idle notification: contexts disposed"); |
| 4857 } else { | 4876 } else { |
| 4858 CollectGarbage(NEW_SPACE); | 4877 CollectGarbage(NEW_SPACE, "idle notification"); |
| 4859 } | 4878 } |
| 4860 new_space_.Shrink(); | 4879 new_space_.Shrink(); |
| 4861 last_idle_notification_gc_count_ = gc_count_; | 4880 last_idle_notification_gc_count_ = gc_count_; |
| 4862 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { | 4881 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { |
| 4863 // Before doing the mark-sweep collections we clear the | 4882 // Before doing the mark-sweep collections we clear the |
| 4864 // compilation cache to avoid hanging on to source code and | 4883 // compilation cache to avoid hanging on to source code and |
| 4865 // generated code for cached functions. | 4884 // generated code for cached functions. |
| 4866 isolate_->compilation_cache()->Clear(); | 4885 isolate_->compilation_cache()->Clear(); |
| 4867 | 4886 |
| 4868 CollectAllGarbage(kNoGCFlags); | 4887 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
| 4869 new_space_.Shrink(); | 4888 new_space_.Shrink(); |
| 4870 last_idle_notification_gc_count_ = gc_count_; | 4889 last_idle_notification_gc_count_ = gc_count_; |
| 4871 | 4890 |
| 4872 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { | 4891 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
| 4873 CollectAllGarbage(kNoGCFlags); | 4892 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
| 4874 new_space_.Shrink(); | 4893 new_space_.Shrink(); |
| 4875 last_idle_notification_gc_count_ = gc_count_; | 4894 last_idle_notification_gc_count_ = gc_count_; |
| 4876 number_idle_notifications_ = 0; | 4895 number_idle_notifications_ = 0; |
| 4877 finished = true; | 4896 finished = true; |
| 4878 } else if (contexts_disposed_ > 0) { | 4897 } else if (contexts_disposed_ > 0) { |
| 4879 if (FLAG_expose_gc) { | 4898 if (FLAG_expose_gc) { |
| 4880 contexts_disposed_ = 0; | 4899 contexts_disposed_ = 0; |
| 4881 } else { | 4900 } else { |
| 4882 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4901 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4883 CollectAllGarbage(kNoGCFlags); | 4902 CollectAllGarbage(kReduceMemoryFootprintMask, |
| 4903 "idle notification: contexts disposed"); |
| 4884 last_idle_notification_gc_count_ = gc_count_; | 4904 last_idle_notification_gc_count_ = gc_count_; |
| 4885 } | 4905 } |
| 4886 // If this is the first idle notification, we reset the | 4906 // If this is the first idle notification, we reset the |
| 4887 // notification count to avoid letting idle notifications for | 4907 // notification count to avoid letting idle notifications for |
| 4888 // context disposal garbage collections start a potentially too | 4908 // context disposal garbage collections start a potentially too |
| 4889 // aggressive idle GC cycle. | 4909 // aggressive idle GC cycle. |
| 4890 if (number_idle_notifications_ <= 1) { | 4910 if (number_idle_notifications_ <= 1) { |
| 4891 number_idle_notifications_ = 0; | 4911 number_idle_notifications_ = 0; |
| 4892 uncommit = false; | 4912 uncommit = false; |
| 4893 } | 4913 } |
| (...skipping 1610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6504 OldSpaces spaces; | 6524 OldSpaces spaces; |
| 6505 for (OldSpace* space = spaces.next(); | 6525 for (OldSpace* space = spaces.next(); |
| 6506 space != NULL; | 6526 space != NULL; |
| 6507 space = spaces.next()) { | 6527 space = spaces.next()) { |
| 6508 holes_size += space->Waste() + space->Available(); | 6528 holes_size += space->Waste() + space->Available(); |
| 6509 } | 6529 } |
| 6510 return holes_size; | 6530 return holes_size; |
| 6511 } | 6531 } |
| 6512 | 6532 |
| 6513 | 6533 |
| 6514 GCTracer::GCTracer(Heap* heap) | 6534 GCTracer::GCTracer(Heap* heap, |
| 6535 const char* gc_reason, |
| 6536 const char* collector_reason) |
| 6515 : start_time_(0.0), | 6537 : start_time_(0.0), |
| 6516 start_size_(0), | 6538 start_object_size_(0), |
| 6539 start_memory_size_(0), |
| 6517 gc_count_(0), | 6540 gc_count_(0), |
| 6518 full_gc_count_(0), | 6541 full_gc_count_(0), |
| 6519 allocated_since_last_gc_(0), | 6542 allocated_since_last_gc_(0), |
| 6520 spent_in_mutator_(0), | 6543 spent_in_mutator_(0), |
| 6521 promoted_objects_size_(0), | 6544 promoted_objects_size_(0), |
| 6522 heap_(heap) { | 6545 heap_(heap), |
| 6546 gc_reason_(gc_reason), |
| 6547 collector_reason_(collector_reason) { |
| 6523 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6548 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6524 start_time_ = OS::TimeCurrentMillis(); | 6549 start_time_ = OS::TimeCurrentMillis(); |
| 6525 start_size_ = heap_->SizeOfObjects(); | 6550 start_object_size_ = heap_->SizeOfObjects(); |
| 6551 start_memory_size_ = heap_->isolate()->memory_allocator()->Size(); |
| 6526 | 6552 |
| 6527 for (int i = 0; i < Scope::kNumberOfScopes; i++) { | 6553 for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
| 6528 scopes_[i] = 0; | 6554 scopes_[i] = 0; |
| 6529 } | 6555 } |
| 6530 | 6556 |
| 6531 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); | 6557 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); |
| 6532 | 6558 |
| 6533 allocated_since_last_gc_ = | 6559 allocated_since_last_gc_ = |
| 6534 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; | 6560 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; |
| 6535 | 6561 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 6565 heap_->alive_after_last_gc_); | 6591 heap_->alive_after_last_gc_); |
| 6566 if (!first_gc) { | 6592 if (!first_gc) { |
| 6567 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_, | 6593 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_, |
| 6568 static_cast<int>(spent_in_mutator_)); | 6594 static_cast<int>(spent_in_mutator_)); |
| 6569 } | 6595 } |
| 6570 } | 6596 } |
| 6571 | 6597 |
| 6572 if (!FLAG_trace_gc_nvp) { | 6598 if (!FLAG_trace_gc_nvp) { |
| 6573 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); | 6599 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); |
| 6574 | 6600 |
| 6575 PrintF("%s %.1f -> %.1f MB, ", | 6601 double end_memory_size_mb = |
| 6602 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB; |
| 6603 |
| 6604 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", |
| 6576 CollectorString(), | 6605 CollectorString(), |
| 6577 static_cast<double>(start_size_) / MB, | 6606 static_cast<double>(start_object_size_) / MB, |
| 6578 SizeOfHeapObjects()); | 6607 static_cast<double>(start_memory_size_) / MB, |
| 6608 SizeOfHeapObjects(), |
| 6609 end_memory_size_mb); |
| 6579 | 6610 |
| 6580 if (external_time > 0) PrintF("%d / ", external_time); | 6611 if (external_time > 0) PrintF("%d / ", external_time); |
| 6581 PrintF("%d ms", time); | 6612 PrintF("%d ms", time); |
| 6582 if (steps_count_ > 0) { | 6613 if (steps_count_ > 0) { |
| 6583 if (collector_ == SCAVENGER) { | 6614 if (collector_ == SCAVENGER) { |
| 6584 PrintF(" (+ %d ms in %d steps since last GC)", | 6615 PrintF(" (+ %d ms in %d steps since last GC)", |
| 6585 static_cast<int>(steps_took_since_last_gc_), | 6616 static_cast<int>(steps_took_since_last_gc_), |
| 6586 steps_count_since_last_gc_); | 6617 steps_count_since_last_gc_); |
| 6587 } else { | 6618 } else { |
| 6588 PrintF(" (+ %d ms in %d steps since start of marking, " | 6619 PrintF(" (+ %d ms in %d steps since start of marking, " |
| 6589 "biggest step %f ms)", | 6620 "biggest step %f ms)", |
| 6590 static_cast<int>(steps_took_), | 6621 static_cast<int>(steps_took_), |
| 6591 steps_count_, | 6622 steps_count_, |
| 6592 longest_step_); | 6623 longest_step_); |
| 6593 } | 6624 } |
| 6594 } | 6625 } |
| 6626 |
| 6627 if (gc_reason_ != NULL) { |
| 6628 PrintF(" [%s]", gc_reason_); |
| 6629 } |
| 6630 |
| 6631 if (collector_reason_ != NULL) { |
| 6632 PrintF(" [%s]", collector_reason_); |
| 6633 } |
| 6634 |
| 6595 PrintF(".\n"); | 6635 PrintF(".\n"); |
| 6596 } else { | 6636 } else { |
| 6597 PrintF("pause=%d ", time); | 6637 PrintF("pause=%d ", time); |
| 6598 PrintF("mutator=%d ", | 6638 PrintF("mutator=%d ", |
| 6599 static_cast<int>(spent_in_mutator_)); | 6639 static_cast<int>(spent_in_mutator_)); |
| 6600 | 6640 |
| 6601 PrintF("gc="); | 6641 PrintF("gc="); |
| 6602 switch (collector_) { | 6642 switch (collector_) { |
| 6603 case SCAVENGER: | 6643 case SCAVENGER: |
| 6604 PrintF("s"); | 6644 PrintF("s"); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 6622 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS])); | 6662 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS])); |
| 6623 PrintF("old_new=%d ", | 6663 PrintF("old_new=%d ", |
| 6624 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS])); | 6664 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS])); |
| 6625 PrintF("compaction_ptrs=%d ", | 6665 PrintF("compaction_ptrs=%d ", |
| 6626 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED])); | 6666 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED])); |
| 6627 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[ | 6667 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[ |
| 6628 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED])); | 6668 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED])); |
| 6629 PrintF("misc_compaction=%d ", | 6669 PrintF("misc_compaction=%d ", |
| 6630 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS])); | 6670 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS])); |
| 6631 | 6671 |
| 6632 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); | 6672 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_); |
| 6633 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); | 6673 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); |
| 6634 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", | 6674 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", |
| 6635 in_free_list_or_wasted_before_gc_); | 6675 in_free_list_or_wasted_before_gc_); |
| 6636 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); | 6676 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); |
| 6637 | 6677 |
| 6638 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); | 6678 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); |
| 6639 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); | 6679 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); |
| 6640 | 6680 |
| 6641 if (collector_ == SCAVENGER) { | 6681 if (collector_ == SCAVENGER) { |
| 6642 PrintF("stepscount=%d ", steps_count_since_last_gc_); | 6682 PrintF("stepscount=%d ", steps_count_since_last_gc_); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6838 isolate_->heap()->store_buffer()->Compact(); | 6878 isolate_->heap()->store_buffer()->Compact(); |
| 6839 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); | 6879 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6840 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 6880 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6841 next = chunk->next_chunk(); | 6881 next = chunk->next_chunk(); |
| 6842 isolate_->memory_allocator()->Free(chunk); | 6882 isolate_->memory_allocator()->Free(chunk); |
| 6843 } | 6883 } |
| 6844 chunks_queued_for_free_ = NULL; | 6884 chunks_queued_for_free_ = NULL; |
| 6845 } | 6885 } |
| 6846 | 6886 |
| 6847 } } // namespace v8::internal | 6887 } } // namespace v8::internal |
| OLD | NEW |