| 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 3968 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4602 | 4620 |
| 4603 bool Heap::IsHeapIterable() { | 4621 bool Heap::IsHeapIterable() { |
| 4604 return (!old_pointer_space()->was_swept_conservatively() && | 4622 return (!old_pointer_space()->was_swept_conservatively() && |
| 4605 !old_data_space()->was_swept_conservatively()); | 4623 !old_data_space()->was_swept_conservatively()); |
| 4606 } | 4624 } |
| 4607 | 4625 |
| 4608 | 4626 |
| 4609 void Heap::EnsureHeapIsIterable() { | 4627 void Heap::EnsureHeapIsIterable() { |
| 4610 ASSERT(IsAllocationAllowed()); | 4628 ASSERT(IsAllocationAllowed()); |
| 4611 if (!IsHeapIterable()) { | 4629 if (!IsHeapIterable()) { |
| 4612 CollectAllGarbage(kMakeHeapIterableMask); | 4630 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); |
| 4613 } | 4631 } |
| 4614 ASSERT(IsHeapIterable()); | 4632 ASSERT(IsHeapIterable()); |
| 4615 } | 4633 } |
| 4616 | 4634 |
| 4617 | 4635 |
| 4618 bool Heap::IdleNotification(int hint) { | 4636 bool Heap::IdleNotification(int hint) { |
| 4619 if (hint >= 1000) return IdleGlobalGC(); | 4637 if (hint >= 1000) return IdleGlobalGC(); |
| 4620 if (contexts_disposed_ > 0 || !FLAG_incremental_marking || | 4638 if (contexts_disposed_ > 0 || !FLAG_incremental_marking || |
| 4621 FLAG_expose_gc || Serializer::enabled()) { | 4639 FLAG_expose_gc || Serializer::enabled()) { |
| 4622 return true; | 4640 return true; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4672 incremental_marking()->Step(step_size); | 4690 incremental_marking()->Step(step_size); |
| 4673 idle_notification_will_schedule_next_gc_ = false; | 4691 idle_notification_will_schedule_next_gc_ = false; |
| 4674 | 4692 |
| 4675 if (incremental_marking()->IsComplete()) { | 4693 if (incremental_marking()->IsComplete()) { |
| 4676 bool uncommit = false; | 4694 bool uncommit = false; |
| 4677 if (gc_count_at_last_idle_gc_ == gc_count_) { | 4695 if (gc_count_at_last_idle_gc_ == gc_count_) { |
| 4678 // No GC since the last full GC, the mutator is probably not active. | 4696 // No GC since the last full GC, the mutator is probably not active. |
| 4679 isolate_->compilation_cache()->Clear(); | 4697 isolate_->compilation_cache()->Clear(); |
| 4680 uncommit = true; | 4698 uncommit = true; |
| 4681 } | 4699 } |
| 4682 CollectAllGarbage(kNoGCFlags); | 4700 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); |
| 4683 gc_count_at_last_idle_gc_ = gc_count_; | 4701 gc_count_at_last_idle_gc_ = gc_count_; |
| 4684 if (uncommit) { | 4702 if (uncommit) { |
| 4685 new_space_.Shrink(); | 4703 new_space_.Shrink(); |
| 4686 UncommitFromSpace(); | 4704 UncommitFromSpace(); |
| 4687 } | 4705 } |
| 4688 } | 4706 } |
| 4689 return false; | 4707 return false; |
| 4690 } | 4708 } |
| 4691 | 4709 |
| 4692 | 4710 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4713 number_idle_notifications_ = | 4731 number_idle_notifications_ = |
| 4714 Min(number_idle_notifications_ + 1, kMaxIdleCount); | 4732 Min(number_idle_notifications_ + 1, kMaxIdleCount); |
| 4715 } else { | 4733 } else { |
| 4716 number_idle_notifications_ = 0; | 4734 number_idle_notifications_ = 0; |
| 4717 last_idle_notification_gc_count_ = gc_count_; | 4735 last_idle_notification_gc_count_ = gc_count_; |
| 4718 } | 4736 } |
| 4719 | 4737 |
| 4720 if (number_idle_notifications_ == kIdlesBeforeScavenge) { | 4738 if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
| 4721 if (contexts_disposed_ > 0) { | 4739 if (contexts_disposed_ > 0) { |
| 4722 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4740 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4723 CollectAllGarbage(kNoGCFlags); | 4741 CollectAllGarbage(kReduceMemoryFootprintMask, |
| 4742 "idle notification: contexts disposed"); |
| 4724 } else { | 4743 } else { |
| 4725 CollectGarbage(NEW_SPACE); | 4744 CollectGarbage(NEW_SPACE, "idle notification"); |
| 4726 } | 4745 } |
| 4727 new_space_.Shrink(); | 4746 new_space_.Shrink(); |
| 4728 last_idle_notification_gc_count_ = gc_count_; | 4747 last_idle_notification_gc_count_ = gc_count_; |
| 4729 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { | 4748 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { |
| 4730 // Before doing the mark-sweep collections we clear the | 4749 // Before doing the mark-sweep collections we clear the |
| 4731 // compilation cache to avoid hanging on to source code and | 4750 // compilation cache to avoid hanging on to source code and |
| 4732 // generated code for cached functions. | 4751 // generated code for cached functions. |
| 4733 isolate_->compilation_cache()->Clear(); | 4752 isolate_->compilation_cache()->Clear(); |
| 4734 | 4753 |
| 4735 CollectAllGarbage(kNoGCFlags); | 4754 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
| 4736 new_space_.Shrink(); | 4755 new_space_.Shrink(); |
| 4737 last_idle_notification_gc_count_ = gc_count_; | 4756 last_idle_notification_gc_count_ = gc_count_; |
| 4738 | 4757 |
| 4739 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { | 4758 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
| 4740 CollectAllGarbage(kNoGCFlags); | 4759 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
| 4741 new_space_.Shrink(); | 4760 new_space_.Shrink(); |
| 4742 last_idle_notification_gc_count_ = gc_count_; | 4761 last_idle_notification_gc_count_ = gc_count_; |
| 4743 number_idle_notifications_ = 0; | 4762 number_idle_notifications_ = 0; |
| 4744 finished = true; | 4763 finished = true; |
| 4745 } else if (contexts_disposed_ > 0) { | 4764 } else if (contexts_disposed_ > 0) { |
| 4746 if (FLAG_expose_gc) { | 4765 if (FLAG_expose_gc) { |
| 4747 contexts_disposed_ = 0; | 4766 contexts_disposed_ = 0; |
| 4748 } else { | 4767 } else { |
| 4749 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4768 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4750 CollectAllGarbage(kNoGCFlags); | 4769 CollectAllGarbage(kReduceMemoryFootprintMask, |
| 4770 "idle notification: contexts disposed"); |
| 4751 last_idle_notification_gc_count_ = gc_count_; | 4771 last_idle_notification_gc_count_ = gc_count_; |
| 4752 } | 4772 } |
| 4753 // If this is the first idle notification, we reset the | 4773 // If this is the first idle notification, we reset the |
| 4754 // notification count to avoid letting idle notifications for | 4774 // notification count to avoid letting idle notifications for |
| 4755 // context disposal garbage collections start a potentially too | 4775 // context disposal garbage collections start a potentially too |
| 4756 // aggressive idle GC cycle. | 4776 // aggressive idle GC cycle. |
| 4757 if (number_idle_notifications_ <= 1) { | 4777 if (number_idle_notifications_ <= 1) { |
| 4758 number_idle_notifications_ = 0; | 4778 number_idle_notifications_ = 0; |
| 4759 uncommit = false; | 4779 uncommit = false; |
| 4760 } | 4780 } |
| (...skipping 1610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6371 OldSpaces spaces; | 6391 OldSpaces spaces; |
| 6372 for (OldSpace* space = spaces.next(); | 6392 for (OldSpace* space = spaces.next(); |
| 6373 space != NULL; | 6393 space != NULL; |
| 6374 space = spaces.next()) { | 6394 space = spaces.next()) { |
| 6375 holes_size += space->Waste() + space->Available(); | 6395 holes_size += space->Waste() + space->Available(); |
| 6376 } | 6396 } |
| 6377 return holes_size; | 6397 return holes_size; |
| 6378 } | 6398 } |
| 6379 | 6399 |
| 6380 | 6400 |
| 6381 GCTracer::GCTracer(Heap* heap) | 6401 GCTracer::GCTracer(Heap* heap, |
| 6402 const char* gc_reason, |
| 6403 const char* collector_reason) |
| 6382 : start_time_(0.0), | 6404 : start_time_(0.0), |
| 6383 start_size_(0), | 6405 start_size_(0), |
| 6384 gc_count_(0), | 6406 gc_count_(0), |
| 6385 full_gc_count_(0), | 6407 full_gc_count_(0), |
| 6386 allocated_since_last_gc_(0), | 6408 allocated_since_last_gc_(0), |
| 6387 spent_in_mutator_(0), | 6409 spent_in_mutator_(0), |
| 6388 promoted_objects_size_(0), | 6410 promoted_objects_size_(0), |
| 6389 heap_(heap) { | 6411 heap_(heap), |
| 6412 gc_reason_(gc_reason), |
| 6413 collector_reason_(collector_reason) { |
| 6390 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | 6414 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 6391 start_time_ = OS::TimeCurrentMillis(); | 6415 start_time_ = OS::TimeCurrentMillis(); |
| 6392 start_size_ = heap_->SizeOfObjects(); | 6416 start_size_ = heap_->SizeOfObjects(); |
| 6393 | 6417 |
| 6394 for (int i = 0; i < Scope::kNumberOfScopes; i++) { | 6418 for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
| 6395 scopes_[i] = 0; | 6419 scopes_[i] = 0; |
| 6396 } | 6420 } |
| 6397 | 6421 |
| 6398 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); | 6422 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(); |
| 6399 | 6423 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6452 static_cast<int>(steps_took_since_last_gc_), | 6476 static_cast<int>(steps_took_since_last_gc_), |
| 6453 steps_count_since_last_gc_); | 6477 steps_count_since_last_gc_); |
| 6454 } else { | 6478 } else { |
| 6455 PrintF(" (+ %d ms in %d steps since start of marking, " | 6479 PrintF(" (+ %d ms in %d steps since start of marking, " |
| 6456 "biggest step %f ms)", | 6480 "biggest step %f ms)", |
| 6457 static_cast<int>(steps_took_), | 6481 static_cast<int>(steps_took_), |
| 6458 steps_count_, | 6482 steps_count_, |
| 6459 longest_step_); | 6483 longest_step_); |
| 6460 } | 6484 } |
| 6461 } | 6485 } |
| 6486 |
| 6487 if (gc_reason_ != NULL) { |
| 6488 PrintF(" [%s]", gc_reason_); |
| 6489 } |
| 6490 |
| 6491 if (collector_reason_ != NULL) { |
| 6492 PrintF(" [%s]", collector_reason_); |
| 6493 } |
| 6494 |
| 6462 PrintF(".\n"); | 6495 PrintF(".\n"); |
| 6463 } else { | 6496 } else { |
| 6464 PrintF("pause=%d ", time); | 6497 PrintF("pause=%d ", time); |
| 6465 PrintF("mutator=%d ", | 6498 PrintF("mutator=%d ", |
| 6466 static_cast<int>(spent_in_mutator_)); | 6499 static_cast<int>(spent_in_mutator_)); |
| 6467 | 6500 |
| 6468 PrintF("gc="); | 6501 PrintF("gc="); |
| 6469 switch (collector_) { | 6502 switch (collector_) { |
| 6470 case SCAVENGER: | 6503 case SCAVENGER: |
| 6471 PrintF("s"); | 6504 PrintF("s"); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6709 isolate_->heap()->store_buffer()->Compact(); | 6742 isolate_->heap()->store_buffer()->Compact(); |
| 6710 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); | 6743 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6711 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 6744 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6712 next = chunk->next_chunk(); | 6745 next = chunk->next_chunk(); |
| 6713 isolate_->memory_allocator()->Free(chunk); | 6746 isolate_->memory_allocator()->Free(chunk); |
| 6714 } | 6747 } |
| 6715 chunks_queued_for_free_ = NULL; | 6748 chunks_queued_for_free_ = NULL; |
| 6716 } | 6749 } |
| 6717 | 6750 |
| 6718 } } // namespace v8::internal | 6751 } } // namespace v8::internal |
| OLD | NEW |