Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: src/heap/mark-compact.cc

Issue 1024823002: Fix OOM bug 3976. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Add test from bug Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/base/atomicops.h" 7 #include "src/base/atomicops.h"
8 #include "src/base/bits.h" 8 #include "src/base/bits.h"
9 #include "src/code-stubs.h" 9 #include "src/code-stubs.h"
10 #include "src/compilation-cache.h" 10 #include "src/compilation-cache.h"
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 return NULL; 588 return NULL;
589 } 589 }
590 590
591 591
592 // Returns zero for pages that have so little fragmentation that it is not 592 // Returns zero for pages that have so little fragmentation that it is not
593 // worth defragmenting them. Otherwise a positive integer that gives an 593 // worth defragmenting them. Otherwise a positive integer that gives an
594 // estimate of fragmentation on an arbitrary scale. 594 // estimate of fragmentation on an arbitrary scale.
595 static int FreeListFragmentation(PagedSpace* space, Page* p) { 595 static int FreeListFragmentation(PagedSpace* space, Page* p) {
596 // If page was not swept then there are no free list items on it. 596 // If page was not swept then there are no free list items on it.
597 if (!p->WasSwept()) { 597 if (!p->WasSwept()) {
598 if (FLAG_trace_fragmentation) { 598 if (FLAG_trace_fragmentation_verbose) {
599 PrintF("%p [%s]: %d bytes live (unswept)\n", reinterpret_cast<void*>(p), 599 PrintF("%p [%s]: %d bytes live (unswept)\n", reinterpret_cast<void*>(p),
600 AllocationSpaceName(space->identity()), p->LiveBytes()); 600 AllocationSpaceName(space->identity()), p->LiveBytes());
601 } 601 }
602 return 0; 602 return FLAG_always_compact ? 1 : 0;
603 } 603 }
604 604
605 PagedSpace::SizeStats sizes; 605 PagedSpace::SizeStats sizes;
606 space->ObtainFreeListStatistics(p, &sizes); 606 space->ObtainFreeListStatistics(p, &sizes);
607 607
608 intptr_t ratio; 608 intptr_t ratio;
609 intptr_t ratio_threshold; 609 intptr_t ratio_threshold;
610 intptr_t area_size = space->AreaSize(); 610 intptr_t area_size = space->AreaSize();
611 if (space->identity() == CODE_SPACE) { 611 if (space->identity() == CODE_SPACE) {
612 ratio = (sizes.medium_size_ * 10 + sizes.large_size_ * 2) * 100 / area_size; 612 ratio = (sizes.medium_size_ * 10 + sizes.large_size_ * 2) * 100 / area_size;
613 ratio_threshold = 10; 613 ratio_threshold = 10;
614 } else { 614 } else {
615 ratio = (sizes.small_size_ * 5 + sizes.medium_size_) * 100 / area_size; 615 ratio = (sizes.small_size_ * 5 + sizes.medium_size_) * 100 / area_size;
616 ratio_threshold = 15; 616 ratio_threshold = 15;
617 } 617 }
618 618
619 if (FLAG_trace_fragmentation) { 619 if (FLAG_trace_fragmentation_verbose) {
620 PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n", 620 PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n",
621 reinterpret_cast<void*>(p), AllocationSpaceName(space->identity()), 621 reinterpret_cast<void*>(p), AllocationSpaceName(space->identity()),
622 static_cast<int>(sizes.small_size_), 622 static_cast<int>(sizes.small_size_),
623 static_cast<double>(sizes.small_size_ * 100) / area_size, 623 static_cast<double>(sizes.small_size_ * 100) / area_size,
624 static_cast<int>(sizes.medium_size_), 624 static_cast<int>(sizes.medium_size_),
625 static_cast<double>(sizes.medium_size_ * 100) / area_size, 625 static_cast<double>(sizes.medium_size_ * 100) / area_size,
626 static_cast<int>(sizes.large_size_), 626 static_cast<int>(sizes.large_size_),
627 static_cast<double>(sizes.large_size_ * 100) / area_size, 627 static_cast<double>(sizes.large_size_ * 100) / area_size,
628 static_cast<int>(sizes.huge_size_), 628 static_cast<int>(sizes.huge_size_),
629 static_cast<double>(sizes.huge_size_ * 100) / area_size, 629 static_cast<double>(sizes.huge_size_ * 100) / area_size,
630 (ratio > ratio_threshold) ? "[fragmented]" : ""); 630 (ratio > ratio_threshold) ? "[fragmented]" : "");
631 } 631 }
632 632
633 if (FLAG_always_compact && sizes.Total() != area_size) { 633 if (FLAG_always_compact && sizes.Total() != area_size) {
634 return 1; 634 return 1;
635 } 635 }
636 636
637 if (ratio <= ratio_threshold) return 0; // Not fragmented. 637 if (ratio <= ratio_threshold) return 0; // Not fragmented.
638 638
639 return static_cast<int>(ratio - ratio_threshold); 639 return static_cast<int>(ratio - ratio_threshold);
640 } 640 }
641 641
642 642
643 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { 643 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
644 DCHECK(space->identity() == OLD_POINTER_SPACE || 644 DCHECK(space->identity() == OLD_POINTER_SPACE ||
645 space->identity() == OLD_DATA_SPACE || 645 space->identity() == OLD_DATA_SPACE ||
646 space->identity() == CODE_SPACE); 646 space->identity() == CODE_SPACE);
647 647
648 static const int kMaxMaxEvacuationCandidates = 1000; 648 static const int kMaxMaxEvacuationCandidates = 10000;
ulan 2015/03/20 10:56:53 Does this help? I think 1000 pages (1GB) should be
Erik Corry 2015/03/20 11:39:23 That rather depends on the total heap size. Not e
649 int number_of_pages = space->CountTotalPages(); 649 int number_of_pages = space->CountTotalPages();
650 int max_evacuation_candidates = 650 int max_evacuation_candidates =
651 static_cast<int>(std::sqrt(number_of_pages / 2.0) + 1); 651 static_cast<int>(std::sqrt(number_of_pages / 2.0) + 1);
652 652
653 if (FLAG_stress_compaction || FLAG_always_compact) { 653 if (FLAG_stress_compaction || FLAG_always_compact) {
654 max_evacuation_candidates = kMaxMaxEvacuationCandidates; 654 max_evacuation_candidates = kMaxMaxEvacuationCandidates;
655 } 655 }
656 656
657 class Candidate { 657 class Candidate {
658 public: 658 public:
(...skipping 26 matching lines...) Expand all
685 685
686 686
687 if (over_reserved > reserved / 3 && over_reserved >= 2 * space->AreaSize()) { 687 if (over_reserved > reserved / 3 && over_reserved >= 2 * space->AreaSize()) {
688 // If over-usage is very high (more than a third of the space), we 688 // If over-usage is very high (more than a third of the space), we
689 // try to free all mostly empty pages. We expect that almost empty 689 // try to free all mostly empty pages. We expect that almost empty
690 // pages are even easier to compact so bump the limit even more. 690 // pages are even easier to compact so bump the limit even more.
691 mode = REDUCE_MEMORY_FOOTPRINT; 691 mode = REDUCE_MEMORY_FOOTPRINT;
692 max_evacuation_candidates *= 2; 692 max_evacuation_candidates *= 2;
693 } 693 }
694 694
695 if (FLAG_always_compact) {
696 max_evacuation_candidates = kMaxMaxEvacuationCandidates;
697 }
698
695 if (FLAG_trace_fragmentation && mode == REDUCE_MEMORY_FOOTPRINT) { 699 if (FLAG_trace_fragmentation && mode == REDUCE_MEMORY_FOOTPRINT) {
696 PrintF( 700 PrintF(
697 "Estimated over reserved memory: %.1f / %.1f MB (threshold %d), " 701 "Estimated over reserved memory: %.1f / %.1f MB (threshold %d), "
698 "evacuation candidate limit: %d\n", 702 "evacuation candidate limit: %d\n",
699 static_cast<double>(over_reserved) / MB, 703 static_cast<double>(over_reserved) / MB,
700 static_cast<double>(reserved) / MB, 704 static_cast<double>(reserved) / MB,
701 static_cast<int>(kFreenessThreshold), max_evacuation_candidates); 705 static_cast<int>(kFreenessThreshold), max_evacuation_candidates);
702 } 706 }
703 707
704 intptr_t estimated_release = 0; 708 intptr_t estimated_release = 0;
(...skipping 11 matching lines...) Expand all
716 if (it.has_next()) it.next(); // Never compact the first page. 720 if (it.has_next()) it.next(); // Never compact the first page.
717 721
718 while (it.has_next()) { 722 while (it.has_next()) {
719 Page* p = it.next(); 723 Page* p = it.next();
720 p->ClearEvacuationCandidate(); 724 p->ClearEvacuationCandidate();
721 725
722 if (FLAG_stress_compaction) { 726 if (FLAG_stress_compaction) {
723 unsigned int counter = space->heap()->ms_count(); 727 unsigned int counter = space->heap()->ms_count();
724 uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits; 728 uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits;
725 if ((counter & 1) == (page_number & 1)) fragmentation = 1; 729 if ((counter & 1) == (page_number & 1)) fragmentation = 1;
726 } else if (mode == REDUCE_MEMORY_FOOTPRINT) { 730 } else if (mode == REDUCE_MEMORY_FOOTPRINT && !FLAG_always_compact) {
727 // Don't try to release too many pages. 731 // Don't try to release too many pages.
728 if (estimated_release >= over_reserved) { 732 if (estimated_release >= over_reserved) {
729 continue; 733 continue;
730 } 734 }
731 735
732 intptr_t free_bytes = 0; 736 intptr_t free_bytes = 0;
733 737
734 if (!p->WasSwept()) { 738 if (!p->WasSwept()) {
735 free_bytes = (p->area_size() - p->LiveBytes()); 739 free_bytes = (p->area_size() - p->LiveBytes());
736 } else { 740 } else {
737 PagedSpace::SizeStats sizes; 741 PagedSpace::SizeStats sizes;
738 space->ObtainFreeListStatistics(p, &sizes); 742 space->ObtainFreeListStatistics(p, &sizes);
739 free_bytes = sizes.Total(); 743 free_bytes = sizes.Total();
740 } 744 }
741 745
742 int free_pct = static_cast<int>(free_bytes * 100) / p->area_size(); 746 int free_pct = static_cast<int>(free_bytes * 100) / p->area_size();
743 747
744 if (free_pct >= kFreenessThreshold) { 748 if (free_pct >= kFreenessThreshold) {
745 estimated_release += free_bytes; 749 estimated_release += free_bytes;
746 fragmentation = free_pct; 750 fragmentation = free_pct;
747 } else { 751 } else {
748 fragmentation = 0; 752 fragmentation = 0;
749 } 753 }
750 754
751 if (FLAG_trace_fragmentation) { 755 if (FLAG_trace_fragmentation_verbose) {
752 PrintF("%p [%s]: %d (%.2f%%) free %s\n", reinterpret_cast<void*>(p), 756 PrintF("%p [%s]: %d (%.2f%%) free %s\n", reinterpret_cast<void*>(p),
753 AllocationSpaceName(space->identity()), 757 AllocationSpaceName(space->identity()),
754 static_cast<int>(free_bytes), 758 static_cast<int>(free_bytes),
755 static_cast<double>(free_bytes * 100) / p->area_size(), 759 static_cast<double>(free_bytes * 100) / p->area_size(),
756 (fragmentation > 0) ? "[fragmented]" : ""); 760 (fragmentation > 0) ? "[fragmented]" : "");
757 } 761 }
758 } else { 762 } else {
759 fragmentation = FreeListFragmentation(space, p); 763 fragmentation = FreeListFragmentation(space, p);
760 } 764 }
761 765
(...skipping 2270 matching lines...) Expand 10 before | Expand all | Expand 10 after
3032 3036
3033 // Clear marking bits for current cell. 3037 // Clear marking bits for current cell.
3034 *cell = 0; 3038 *cell = 0;
3035 } 3039 }
3036 p->ResetLiveBytes(); 3040 p->ResetLiveBytes();
3037 } 3041 }
3038 3042
3039 3043
3040 void MarkCompactCollector::EvacuatePages() { 3044 void MarkCompactCollector::EvacuatePages() {
3041 int npages = evacuation_candidates_.length(); 3045 int npages = evacuation_candidates_.length();
3046 int abandoned_pages = 0;
3042 for (int i = 0; i < npages; i++) { 3047 for (int i = 0; i < npages; i++) {
3043 Page* p = evacuation_candidates_[i]; 3048 Page* p = evacuation_candidates_[i];
3044 DCHECK(p->IsEvacuationCandidate() || 3049 DCHECK(p->IsEvacuationCandidate() ||
3045 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3050 p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
3046 DCHECK(static_cast<int>(p->parallel_sweeping()) == 3051 DCHECK(static_cast<int>(p->parallel_sweeping()) ==
3047 MemoryChunk::SWEEPING_DONE); 3052 MemoryChunk::SWEEPING_DONE);
3048 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3053 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
3049 // Allocate emergency memory for the case when compaction fails due to out 3054 // Allocate emergency memory for the case when compaction fails due to out
3050 // of memory. 3055 // of memory.
3051 if (!space->HasEmergencyMemory()) { 3056 if (!space->HasEmergencyMemory()) {
3052 space->CreateEmergencyMemory(); 3057 space->CreateEmergencyMemory();
3053 } 3058 }
3054 if (p->IsEvacuationCandidate()) { 3059 if (p->IsEvacuationCandidate()) {
3055 // During compaction we might have to request a new page. Check that we 3060 // During compaction we might have to request a new page. Check that we
3056 // have an emergency page and the space still has room for that. 3061 // have an emergency page and the space still has room for that.
3057 if (space->HasEmergencyMemory() && space->CanExpand()) { 3062 if (space->HasEmergencyMemory() || space->CanExpand()) {
ulan 2015/03/20 10:56:54 Good catch!
3058 EvacuateLiveObjectsFromPage(p); 3063 EvacuateLiveObjectsFromPage(p);
3059 } else { 3064 } else {
3060 // Without room for expansion evacuation is not guaranteed to succeed. 3065 // Without room for expansion evacuation is not guaranteed to succeed.
3061 // Pessimistically abandon unevacuated pages. 3066 // Pessimistically abandon unevacuated pages.
3062 for (int j = i; j < npages; j++) { 3067 for (int j = i; j < npages; j++) {
3063 Page* page = evacuation_candidates_[j]; 3068 Page* page = evacuation_candidates_[j];
3064 slots_buffer_allocator_.DeallocateChain(page->slots_buffer_address()); 3069 slots_buffer_allocator_.DeallocateChain(page->slots_buffer_address());
3065 page->ClearEvacuationCandidate(); 3070 page->ClearEvacuationCandidate();
3066 page->SetFlag(Page::RESCAN_ON_EVACUATION); 3071 page->SetFlag(Page::RESCAN_ON_EVACUATION);
3067 } 3072 }
3073 abandoned_pages = npages - i;
3068 break; 3074 break;
3069 } 3075 }
3070 } 3076 }
3071 } 3077 }
3072 if (npages > 0) { 3078 if (npages > 0) {
3073 // Release emergency memory. 3079 // Release emergency memory.
3074 PagedSpaces spaces(heap()); 3080 PagedSpaces spaces(heap());
3075 for (PagedSpace* space = spaces.next(); space != NULL; 3081 for (PagedSpace* space = spaces.next(); space != NULL;
3076 space = spaces.next()) { 3082 space = spaces.next()) {
3077 if (space->HasEmergencyMemory()) { 3083 if (space->HasEmergencyMemory()) {
3078 space->FreeEmergencyMemory(); 3084 space->FreeEmergencyMemory();
3079 } 3085 }
3080 } 3086 }
3087 if (FLAG_trace_fragmentation) {
3088 if (abandoned_pages != 0) {
3089 PrintF(
3090 " Abandon %d out of %d page defragmentations due to lack of "
3091 "memory\n",
3092 abandoned_pages, npages);
3093 } else {
3094 PrintF(" Defragmented %d pages\n", npages);
3095 }
3096 }
3081 } 3097 }
3082 } 3098 }
3083 3099
3084 3100
3085 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { 3101 class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
3086 public: 3102 public:
3087 virtual Object* RetainAs(Object* object) { 3103 virtual Object* RetainAs(Object* object) {
3088 if (object->IsHeapObject()) { 3104 if (object->IsHeapObject()) {
3089 HeapObject* heap_object = HeapObject::cast(object); 3105 HeapObject* heap_object = HeapObject::cast(object);
3090 MapWord map_word = heap_object->map_word(); 3106 MapWord map_word = heap_object->map_word();
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
3424 &Heap::ScavengeStoreBufferCallback); 3440 &Heap::ScavengeStoreBufferCallback);
3425 heap_->store_buffer()->IteratePointersToNewSpaceAndClearMaps( 3441 heap_->store_buffer()->IteratePointersToNewSpaceAndClearMaps(
3426 &UpdatePointer); 3442 &UpdatePointer);
3427 } 3443 }
3428 3444
3429 { 3445 {
3430 GCTracer::Scope gc_scope(heap()->tracer(), 3446 GCTracer::Scope gc_scope(heap()->tracer(),
3431 GCTracer::Scope::MC_UPDATE_POINTERS_TO_EVACUATED); 3447 GCTracer::Scope::MC_UPDATE_POINTERS_TO_EVACUATED);
3432 SlotsBuffer::UpdateSlotsRecordedIn(heap_, migration_slots_buffer_, 3448 SlotsBuffer::UpdateSlotsRecordedIn(heap_, migration_slots_buffer_,
3433 code_slots_filtering_required); 3449 code_slots_filtering_required);
3434 if (FLAG_trace_fragmentation) { 3450 if (FLAG_trace_fragmentation_verbose) {
3435 PrintF(" migration slots buffer: %d\n", 3451 PrintF(" migration slots buffer: %d\n",
3436 SlotsBuffer::SizeOfChain(migration_slots_buffer_)); 3452 SlotsBuffer::SizeOfChain(migration_slots_buffer_));
3437 } 3453 }
3438 3454
3439 if (compacting_ && was_marked_incrementally_) { 3455 if (compacting_ && was_marked_incrementally_) {
3440 // It's difficult to filter out slots recorded for large objects. 3456 // It's difficult to filter out slots recorded for large objects.
3441 LargeObjectIterator it(heap_->lo_space()); 3457 LargeObjectIterator it(heap_->lo_space());
3442 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { 3458 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
3443 // LargeObjectSpace is not swept yet thus we have to skip 3459 // LargeObjectSpace is not swept yet thus we have to skip
3444 // dead objects explicitly. 3460 // dead objects explicitly.
(...skipping 14 matching lines...) Expand all
3459 heap()->tracer(), 3475 heap()->tracer(),
3460 GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED); 3476 GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED);
3461 for (int i = 0; i < npages; i++) { 3477 for (int i = 0; i < npages; i++) {
3462 Page* p = evacuation_candidates_[i]; 3478 Page* p = evacuation_candidates_[i];
3463 DCHECK(p->IsEvacuationCandidate() || 3479 DCHECK(p->IsEvacuationCandidate() ||
3464 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3480 p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
3465 3481
3466 if (p->IsEvacuationCandidate()) { 3482 if (p->IsEvacuationCandidate()) {
3467 SlotsBuffer::UpdateSlotsRecordedIn(heap_, p->slots_buffer(), 3483 SlotsBuffer::UpdateSlotsRecordedIn(heap_, p->slots_buffer(),
3468 code_slots_filtering_required); 3484 code_slots_filtering_required);
3469 if (FLAG_trace_fragmentation) { 3485 if (FLAG_trace_fragmentation_verbose) {
3470 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), 3486 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p),
3471 SlotsBuffer::SizeOfChain(p->slots_buffer())); 3487 SlotsBuffer::SizeOfChain(p->slots_buffer()));
3472 } 3488 }
3473 3489
3474 // Important: skip list should be cleared only after roots were updated 3490 // Important: skip list should be cleared only after roots were updated
3475 // because root iteration traverses the stack and might have to find 3491 // because root iteration traverses the stack and might have to find
3476 // code objects from non-updated pc pointing into evacuation candidate. 3492 // code objects from non-updated pc pointing into evacuation candidate.
3477 SkipList* list = p->skip_list(); 3493 SkipList* list = p->skip_list();
3478 if (list != NULL) list->Clear(); 3494 if (list != NULL) list->Clear();
3479 } else { 3495 } else {
(...skipping 923 matching lines...) Expand 10 before | Expand all | Expand 10 after
4403 SlotsBuffer* buffer = *buffer_address; 4419 SlotsBuffer* buffer = *buffer_address;
4404 while (buffer != NULL) { 4420 while (buffer != NULL) {
4405 SlotsBuffer* next_buffer = buffer->next(); 4421 SlotsBuffer* next_buffer = buffer->next();
4406 DeallocateBuffer(buffer); 4422 DeallocateBuffer(buffer);
4407 buffer = next_buffer; 4423 buffer = next_buffer;
4408 } 4424 }
4409 *buffer_address = NULL; 4425 *buffer_address = NULL;
4410 } 4426 }
4411 } 4427 }
4412 } // namespace v8::internal 4428 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/flag-definitions.h ('k') | src/hydrogen.cc » ('j') | src/hydrogen.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698