| OLD | NEW |
| 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/heap/heap.h" | 5 #include "src/heap/heap.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/api.h" | 8 #include "src/api.h" |
| 9 #include "src/ast/context-slot-cache.h" | 9 #include "src/ast/context-slot-cache.h" |
| 10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| (...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 }; | 783 }; |
| 784 | 784 |
| 785 | 785 |
| 786 void Heap::HandleGCRequest() { | 786 void Heap::HandleGCRequest() { |
| 787 if (HighMemoryPressure()) { | 787 if (HighMemoryPressure()) { |
| 788 incremental_marking()->reset_request_type(); | 788 incremental_marking()->reset_request_type(); |
| 789 CheckMemoryPressure(); | 789 CheckMemoryPressure(); |
| 790 } else if (incremental_marking()->request_type() == | 790 } else if (incremental_marking()->request_type() == |
| 791 IncrementalMarking::COMPLETE_MARKING) { | 791 IncrementalMarking::COMPLETE_MARKING) { |
| 792 incremental_marking()->reset_request_type(); | 792 incremental_marking()->reset_request_type(); |
| 793 CollectAllGarbage(current_gc_flags_, "GC interrupt", | 793 CollectAllGarbage(current_gc_flags_, |
| 794 GarbageCollectionReason::kFinalizeMarkingViaStackGuard, |
| 794 current_gc_callback_flags_); | 795 current_gc_callback_flags_); |
| 795 } else if (incremental_marking()->request_type() == | 796 } else if (incremental_marking()->request_type() == |
| 796 IncrementalMarking::FINALIZATION && | 797 IncrementalMarking::FINALIZATION && |
| 797 incremental_marking()->IsMarking() && | 798 incremental_marking()->IsMarking() && |
| 798 !incremental_marking()->finalize_marking_completed()) { | 799 !incremental_marking()->finalize_marking_completed()) { |
| 799 incremental_marking()->reset_request_type(); | 800 incremental_marking()->reset_request_type(); |
| 800 FinalizeIncrementalMarking("GC interrupt: finalize incremental marking"); | 801 FinalizeIncrementalMarking( |
| 802 GarbageCollectionReason::kFinalizeMarkingViaStackGuard); |
| 801 } | 803 } |
| 802 } | 804 } |
| 803 | 805 |
| 804 | 806 |
| 805 void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) { | 807 void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) { |
| 806 scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated); | 808 scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated); |
| 807 } | 809 } |
| 808 | 810 |
| 809 | 811 void Heap::FinalizeIncrementalMarking(GarbageCollectionReason gc_reason) { |
| 810 void Heap::FinalizeIncrementalMarking(const char* gc_reason) { | |
| 811 if (FLAG_trace_incremental_marking) { | 812 if (FLAG_trace_incremental_marking) { |
| 812 isolate()->PrintWithTimestamp("[IncrementalMarking] (%s).\n", gc_reason); | 813 isolate()->PrintWithTimestamp("[IncrementalMarking] (%s).\n", gc_reason); |
| 813 } | 814 } |
| 814 | 815 |
| 815 HistogramTimerScope incremental_marking_scope( | 816 HistogramTimerScope incremental_marking_scope( |
| 816 isolate()->counters()->gc_incremental_marking_finalize()); | 817 isolate()->counters()->gc_incremental_marking_finalize()); |
| 817 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingFinalize"); | 818 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingFinalize"); |
| 818 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_FINALIZE); | 819 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_FINALIZE); |
| 819 | 820 |
| 820 { | 821 { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 850 return isolate_->counters()->gc_finalize_reduce_memory(); | 851 return isolate_->counters()->gc_finalize_reduce_memory(); |
| 851 } else { | 852 } else { |
| 852 return isolate_->counters()->gc_finalize(); | 853 return isolate_->counters()->gc_finalize(); |
| 853 } | 854 } |
| 854 } else { | 855 } else { |
| 855 return isolate_->counters()->gc_compactor(); | 856 return isolate_->counters()->gc_compactor(); |
| 856 } | 857 } |
| 857 } | 858 } |
| 858 } | 859 } |
| 859 | 860 |
| 860 void Heap::CollectAllGarbage(int flags, const char* gc_reason, | 861 void Heap::CollectAllGarbage(int flags, GarbageCollectionReason gc_reason, |
| 861 const v8::GCCallbackFlags gc_callback_flags) { | 862 const v8::GCCallbackFlags gc_callback_flags) { |
| 862 // Since we are ignoring the return value, the exact choice of space does | 863 // Since we are ignoring the return value, the exact choice of space does |
| 863 // not matter, so long as we do not specify NEW_SPACE, which would not | 864 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 864 // cause a full GC. | 865 // cause a full GC. |
| 865 set_current_gc_flags(flags); | 866 set_current_gc_flags(flags); |
| 866 CollectGarbage(OLD_SPACE, gc_reason, gc_callback_flags); | 867 CollectGarbage(OLD_SPACE, gc_reason, gc_callback_flags); |
| 867 set_current_gc_flags(kNoGCFlags); | 868 set_current_gc_flags(kNoGCFlags); |
| 868 } | 869 } |
| 869 | 870 |
| 870 | 871 void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) { |
| 871 void Heap::CollectAllAvailableGarbage(const char* gc_reason) { | |
| 872 // Since we are ignoring the return value, the exact choice of space does | 872 // Since we are ignoring the return value, the exact choice of space does |
| 873 // not matter, so long as we do not specify NEW_SPACE, which would not | 873 // not matter, so long as we do not specify NEW_SPACE, which would not |
| 874 // cause a full GC. | 874 // cause a full GC. |
| 875 // Major GC would invoke weak handle callbacks on weakly reachable | 875 // Major GC would invoke weak handle callbacks on weakly reachable |
| 876 // handles, but won't collect weakly reachable objects until next | 876 // handles, but won't collect weakly reachable objects until next |
| 877 // major GC. Therefore if we collect aggressively and weak handle callback | 877 // major GC. Therefore if we collect aggressively and weak handle callback |
| 878 // has been invoked, we rerun major GC to release objects which become | 878 // has been invoked, we rerun major GC to release objects which become |
| 879 // garbage. | 879 // garbage. |
| 880 // Note: as weak callbacks can execute arbitrary code, we cannot | 880 // Note: as weak callbacks can execute arbitrary code, we cannot |
| 881 // hope that eventually there will be no weak callbacks invocations. | 881 // hope that eventually there will be no weak callbacks invocations. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 895 v8::kGCCallbackFlagCollectAllAvailableGarbage) && | 895 v8::kGCCallbackFlagCollectAllAvailableGarbage) && |
| 896 attempt + 1 >= kMinNumberOfAttempts) { | 896 attempt + 1 >= kMinNumberOfAttempts) { |
| 897 break; | 897 break; |
| 898 } | 898 } |
| 899 } | 899 } |
| 900 set_current_gc_flags(kNoGCFlags); | 900 set_current_gc_flags(kNoGCFlags); |
| 901 new_space_->Shrink(); | 901 new_space_->Shrink(); |
| 902 UncommitFromSpace(); | 902 UncommitFromSpace(); |
| 903 } | 903 } |
| 904 | 904 |
| 905 | 905 void Heap::ReportExternalMemoryPressure() { |
| 906 void Heap::ReportExternalMemoryPressure(const char* gc_reason) { | |
| 907 if (external_memory_ > | 906 if (external_memory_ > |
| 908 (external_memory_at_last_mark_compact_ + external_memory_hard_limit())) { | 907 (external_memory_at_last_mark_compact_ + external_memory_hard_limit())) { |
| 909 CollectAllGarbage( | 908 CollectAllGarbage( |
| 910 kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, gc_reason, | 909 kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, |
| 910 GarbageCollectionReason::kExternalMemoryPressure, |
| 911 static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage | | 911 static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage | |
| 912 kGCCallbackFlagCollectAllExternalMemory)); | 912 kGCCallbackFlagCollectAllExternalMemory)); |
| 913 return; | 913 return; |
| 914 } | 914 } |
| 915 if (incremental_marking()->IsStopped()) { | 915 if (incremental_marking()->IsStopped()) { |
| 916 if (incremental_marking()->CanBeActivated()) { | 916 if (incremental_marking()->CanBeActivated()) { |
| 917 StartIncrementalMarking( | 917 StartIncrementalMarking( |
| 918 i::Heap::kNoGCFlags, | 918 i::Heap::kNoGCFlags, GarbageCollectionReason::kExternalMemoryPressure, |
| 919 static_cast<GCCallbackFlags>( | 919 static_cast<GCCallbackFlags>( |
| 920 kGCCallbackFlagSynchronousPhantomCallbackProcessing | | 920 kGCCallbackFlagSynchronousPhantomCallbackProcessing | |
| 921 kGCCallbackFlagCollectAllExternalMemory), | 921 kGCCallbackFlagCollectAllExternalMemory)); |
| 922 gc_reason); | |
| 923 } else { | 922 } else { |
| 924 CollectAllGarbage(i::Heap::kNoGCFlags, gc_reason, | 923 CollectAllGarbage(i::Heap::kNoGCFlags, |
| 924 GarbageCollectionReason::kExternalMemoryPressure, |
| 925 kGCCallbackFlagSynchronousPhantomCallbackProcessing); | 925 kGCCallbackFlagSynchronousPhantomCallbackProcessing); |
| 926 } | 926 } |
| 927 } else { | 927 } else { |
| 928 // Incremental marking is turned on an has already been started. | 928 // Incremental marking is turned on an has already been started. |
| 929 const double pressure = | 929 const double pressure = |
| 930 static_cast<double>(external_memory_ - | 930 static_cast<double>(external_memory_ - |
| 931 external_memory_at_last_mark_compact_ - | 931 external_memory_at_last_mark_compact_ - |
| 932 kExternalAllocationSoftLimit) / | 932 kExternalAllocationSoftLimit) / |
| 933 external_memory_hard_limit(); | 933 external_memory_hard_limit(); |
| 934 DCHECK_GE(1, pressure); | 934 DCHECK_GE(1, pressure); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 948 // may be uninitialized memory behind top. We fill the remainder of the page | 948 // may be uninitialized memory behind top. We fill the remainder of the page |
| 949 // with a filler. | 949 // with a filler. |
| 950 Address to_top = new_space_->top(); | 950 Address to_top = new_space_->top(); |
| 951 Page* page = Page::FromAddress(to_top - kPointerSize); | 951 Page* page = Page::FromAddress(to_top - kPointerSize); |
| 952 if (page->Contains(to_top)) { | 952 if (page->Contains(to_top)) { |
| 953 int remaining_in_page = static_cast<int>(page->area_end() - to_top); | 953 int remaining_in_page = static_cast<int>(page->area_end() - to_top); |
| 954 CreateFillerObjectAt(to_top, remaining_in_page, ClearRecordedSlots::kNo); | 954 CreateFillerObjectAt(to_top, remaining_in_page, ClearRecordedSlots::kNo); |
| 955 } | 955 } |
| 956 } | 956 } |
| 957 | 957 |
| 958 | 958 bool Heap::CollectGarbage(GarbageCollector collector, |
| 959 bool Heap::CollectGarbage(GarbageCollector collector, const char* gc_reason, | 959 GarbageCollectionReason gc_reason, |
| 960 const char* collector_reason, | 960 const char* collector_reason, |
| 961 const v8::GCCallbackFlags gc_callback_flags) { | 961 const v8::GCCallbackFlags gc_callback_flags) { |
| 962 // The VM is in the GC state until exiting this function. | 962 // The VM is in the GC state until exiting this function. |
| 963 VMState<GC> state(isolate_); | 963 VMState<GC> state(isolate_); |
| 964 | 964 |
| 965 #ifdef DEBUG | 965 #ifdef DEBUG |
| 966 // Reset the allocation timeout to the GC interval, but make sure to | 966 // Reset the allocation timeout to the GC interval, but make sure to |
| 967 // allow at least a few allocations after a collection. The reason | 967 // allow at least a few allocations after a collection. The reason |
| 968 // for this is that we have a lot of allocation sequences and we | 968 // for this is that we have a lot of allocation sequences and we |
| 969 // assume that a garbage collection will allow the subsequent | 969 // assume that a garbage collection will allow the subsequent |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 | 1048 |
| 1049 if (collector == MARK_COMPACTOR && | 1049 if (collector == MARK_COMPACTOR && |
| 1050 (gc_callback_flags & (kGCCallbackFlagForced | | 1050 (gc_callback_flags & (kGCCallbackFlagForced | |
| 1051 kGCCallbackFlagCollectAllAvailableGarbage)) != 0) { | 1051 kGCCallbackFlagCollectAllAvailableGarbage)) != 0) { |
| 1052 isolate()->CountUsage(v8::Isolate::kForcedGC); | 1052 isolate()->CountUsage(v8::Isolate::kForcedGC); |
| 1053 } | 1053 } |
| 1054 | 1054 |
| 1055 // Start incremental marking for the next cycle. The heap snapshot | 1055 // Start incremental marking for the next cycle. The heap snapshot |
| 1056 // generator needs incremental marking to stay off after it aborted. | 1056 // generator needs incremental marking to stay off after it aborted. |
| 1057 if (!ShouldAbortIncrementalMarking()) { | 1057 if (!ShouldAbortIncrementalMarking()) { |
| 1058 StartIncrementalMarkingIfNeeded(kNoGCFlags, kNoGCCallbackFlags, | 1058 StartIncrementalMarkingIfAllocationLimitIsReached(kNoGCFlags, |
| 1059 "GC epilogue"); | 1059 kNoGCCallbackFlags); |
| 1060 } | 1060 } |
| 1061 | 1061 |
| 1062 return next_gc_likely_to_collect_more; | 1062 return next_gc_likely_to_collect_more; |
| 1063 } | 1063 } |
| 1064 | 1064 |
| 1065 | 1065 |
| 1066 int Heap::NotifyContextDisposed(bool dependant_context) { | 1066 int Heap::NotifyContextDisposed(bool dependant_context) { |
| 1067 if (!dependant_context) { | 1067 if (!dependant_context) { |
| 1068 tracer()->ResetSurvivalEvents(); | 1068 tracer()->ResetSurvivalEvents(); |
| 1069 old_generation_size_configured_ = false; | 1069 old_generation_size_configured_ = false; |
| 1070 MemoryReducer::Event event; | 1070 MemoryReducer::Event event; |
| 1071 event.type = MemoryReducer::kPossibleGarbage; | 1071 event.type = MemoryReducer::kPossibleGarbage; |
| 1072 event.time_ms = MonotonicallyIncreasingTimeInMs(); | 1072 event.time_ms = MonotonicallyIncreasingTimeInMs(); |
| 1073 memory_reducer_->NotifyPossibleGarbage(event); | 1073 memory_reducer_->NotifyPossibleGarbage(event); |
| 1074 } | 1074 } |
| 1075 if (isolate()->concurrent_recompilation_enabled()) { | 1075 if (isolate()->concurrent_recompilation_enabled()) { |
| 1076 // Flush the queued recompilation tasks. | 1076 // Flush the queued recompilation tasks. |
| 1077 isolate()->optimizing_compile_dispatcher()->Flush(); | 1077 isolate()->optimizing_compile_dispatcher()->Flush(); |
| 1078 } | 1078 } |
| 1079 AgeInlineCaches(); | 1079 AgeInlineCaches(); |
| 1080 number_of_disposed_maps_ = retained_maps()->Length(); | 1080 number_of_disposed_maps_ = retained_maps()->Length(); |
| 1081 tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs()); | 1081 tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs()); |
| 1082 return ++contexts_disposed_; | 1082 return ++contexts_disposed_; |
| 1083 } | 1083 } |
| 1084 | 1084 |
| 1085 | |
| 1086 void Heap::StartIncrementalMarking(int gc_flags, | 1085 void Heap::StartIncrementalMarking(int gc_flags, |
| 1087 const GCCallbackFlags gc_callback_flags, | 1086 GarbageCollectionReason gc_reason, |
| 1088 const char* reason) { | 1087 GCCallbackFlags gc_callback_flags) { |
| 1089 DCHECK(incremental_marking()->IsStopped()); | 1088 DCHECK(incremental_marking()->IsStopped()); |
| 1090 set_current_gc_flags(gc_flags); | 1089 set_current_gc_flags(gc_flags); |
| 1091 current_gc_callback_flags_ = gc_callback_flags; | 1090 current_gc_callback_flags_ = gc_callback_flags; |
| 1092 incremental_marking()->Start(reason); | 1091 incremental_marking()->Start(gc_reason); |
| 1093 } | 1092 } |
| 1094 | 1093 |
| 1095 void Heap::StartIncrementalMarkingIfNeeded( | 1094 void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( |
| 1096 int gc_flags, const GCCallbackFlags gc_callback_flags, const char* reason) { | 1095 int gc_flags, const GCCallbackFlags gc_callback_flags) { |
| 1097 if (incremental_marking()->IsStopped() && | 1096 if (incremental_marking()->IsStopped() && |
| 1098 incremental_marking()->ShouldActivateEvenWithoutIdleNotification()) { | 1097 incremental_marking()->ShouldActivateEvenWithoutIdleNotification()) { |
| 1099 StartIncrementalMarking(gc_flags, gc_callback_flags, reason); | 1098 StartIncrementalMarking(gc_flags, GarbageCollectionReason::kAllocationLimit, |
| 1099 gc_callback_flags); |
| 1100 } | 1100 } |
| 1101 } | 1101 } |
| 1102 | 1102 |
| 1103 void Heap::StartIdleIncrementalMarking() { | 1103 void Heap::StartIdleIncrementalMarking(GarbageCollectionReason gc_reason) { |
| 1104 gc_idle_time_handler_->ResetNoProgressCounter(); | 1104 gc_idle_time_handler_->ResetNoProgressCounter(); |
| 1105 StartIncrementalMarking(kReduceMemoryFootprintMask, kNoGCCallbackFlags, | 1105 StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason, |
| 1106 "idle"); | 1106 kNoGCCallbackFlags); |
| 1107 } | 1107 } |
| 1108 | 1108 |
| 1109 | 1109 |
| 1110 void Heap::MoveElements(FixedArray* array, int dst_index, int src_index, | 1110 void Heap::MoveElements(FixedArray* array, int dst_index, int src_index, |
| 1111 int len) { | 1111 int len) { |
| 1112 if (len == 0) return; | 1112 if (len == 0) return; |
| 1113 | 1113 |
| 1114 DCHECK(array->map() != fixed_cow_array_map()); | 1114 DCHECK(array->map() != fixed_cow_array_map()); |
| 1115 Object** dst_objects = array->data_start() + dst_index; | 1115 Object** dst_objects = array->data_start() + dst_index; |
| 1116 MemMove(dst_objects, array->data_start() + src_index, len * kPointerSize); | 1116 MemMove(dst_objects, array->data_start() + src_index, len * kPointerSize); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1205 chunk.start = free_space_address; | 1205 chunk.start = free_space_address; |
| 1206 chunk.end = free_space_address + size; | 1206 chunk.end = free_space_address + size; |
| 1207 } else { | 1207 } else { |
| 1208 perform_gc = true; | 1208 perform_gc = true; |
| 1209 break; | 1209 break; |
| 1210 } | 1210 } |
| 1211 } | 1211 } |
| 1212 } | 1212 } |
| 1213 if (perform_gc) { | 1213 if (perform_gc) { |
| 1214 if (space == NEW_SPACE) { | 1214 if (space == NEW_SPACE) { |
| 1215 CollectGarbage(NEW_SPACE, "failed to reserve space in the new space"); | 1215 CollectGarbage(NEW_SPACE, GarbageCollectionReason::kDeserializer); |
| 1216 } else { | 1216 } else { |
| 1217 if (counter > 1) { | 1217 if (counter > 1) { |
| 1218 CollectAllGarbage( | 1218 CollectAllGarbage( |
| 1219 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, | 1219 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
| 1220 "failed to reserve space in paged or large " | 1220 GarbageCollectionReason::kDeserializer); |
| 1221 "object space, trying to reduce memory footprint"); | |
| 1222 } else { | 1221 } else { |
| 1223 CollectAllGarbage( | 1222 CollectAllGarbage(kAbortIncrementalMarkingMask, |
| 1224 kAbortIncrementalMarkingMask, | 1223 GarbageCollectionReason::kDeserializer); |
| 1225 "failed to reserve space in paged or large object space"); | |
| 1226 } | 1224 } |
| 1227 } | 1225 } |
| 1228 gc_performed = true; | 1226 gc_performed = true; |
| 1229 break; // Abort for-loop over spaces and retry. | 1227 break; // Abort for-loop over spaces and retry. |
| 1230 } | 1228 } |
| 1231 } | 1229 } |
| 1232 } | 1230 } |
| 1233 | 1231 |
| 1234 return !gc_performed; | 1232 return !gc_performed; |
| 1235 } | 1233 } |
| (...skipping 2833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4069 bool Heap::IsHeapIterable() { | 4067 bool Heap::IsHeapIterable() { |
| 4070 // TODO(hpayer): This function is not correct. Allocation folding in old | 4068 // TODO(hpayer): This function is not correct. Allocation folding in old |
| 4071 // space breaks the iterability. | 4069 // space breaks the iterability. |
| 4072 return new_space_top_after_last_gc_ == new_space()->top(); | 4070 return new_space_top_after_last_gc_ == new_space()->top(); |
| 4073 } | 4071 } |
| 4074 | 4072 |
| 4075 | 4073 |
| 4076 void Heap::MakeHeapIterable() { | 4074 void Heap::MakeHeapIterable() { |
| 4077 DCHECK(AllowHeapAllocation::IsAllowed()); | 4075 DCHECK(AllowHeapAllocation::IsAllowed()); |
| 4078 if (!IsHeapIterable()) { | 4076 if (!IsHeapIterable()) { |
| 4079 CollectAllGarbage(kMakeHeapIterableMask, "Heap::MakeHeapIterable"); | 4077 CollectAllGarbage(kMakeHeapIterableMask, |
| 4078 GarbageCollectionReason::kMakeHeapIterable); |
| 4080 } | 4079 } |
| 4081 if (mark_compact_collector()->sweeping_in_progress()) { | 4080 if (mark_compact_collector()->sweeping_in_progress()) { |
| 4082 mark_compact_collector()->EnsureSweepingCompleted(); | 4081 mark_compact_collector()->EnsureSweepingCompleted(); |
| 4083 } | 4082 } |
| 4084 DCHECK(IsHeapIterable()); | 4083 DCHECK(IsHeapIterable()); |
| 4085 } | 4084 } |
| 4086 | 4085 |
| 4087 | 4086 |
| 4088 static double ComputeMutatorUtilization(double mutator_speed, double gc_speed) { | 4087 static double ComputeMutatorUtilization(double mutator_speed, double gc_speed) { |
| 4089 const double kMinMutatorUtilization = 0.0; | 4088 const double kMinMutatorUtilization = 0.0; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4204 | 4203 |
| 4205 bool Heap::MarkingDequesAreEmpty() { | 4204 bool Heap::MarkingDequesAreEmpty() { |
| 4206 return mark_compact_collector()->marking_deque()->IsEmpty() && | 4205 return mark_compact_collector()->marking_deque()->IsEmpty() && |
| 4207 (!UsingEmbedderHeapTracer() || | 4206 (!UsingEmbedderHeapTracer() || |
| 4208 (mark_compact_collector()->wrappers_to_trace() == 0 && | 4207 (mark_compact_collector()->wrappers_to_trace() == 0 && |
| 4209 mark_compact_collector() | 4208 mark_compact_collector() |
| 4210 ->embedder_heap_tracer() | 4209 ->embedder_heap_tracer() |
| 4211 ->NumberOfWrappersToTrace() == 0)); | 4210 ->NumberOfWrappersToTrace() == 0)); |
| 4212 } | 4211 } |
| 4213 | 4212 |
| 4214 void Heap::FinalizeIncrementalMarkingIfComplete(const char* comment) { | 4213 void Heap::FinalizeIncrementalMarkingIfComplete( |
| 4214 GarbageCollectionReason gc_reason) { |
| 4215 if (incremental_marking()->IsMarking() && | 4215 if (incremental_marking()->IsMarking() && |
| 4216 (incremental_marking()->IsReadyToOverApproximateWeakClosure() || | 4216 (incremental_marking()->IsReadyToOverApproximateWeakClosure() || |
| 4217 (!incremental_marking()->finalize_marking_completed() && | 4217 (!incremental_marking()->finalize_marking_completed() && |
| 4218 MarkingDequesAreEmpty()))) { | 4218 MarkingDequesAreEmpty()))) { |
| 4219 FinalizeIncrementalMarking(comment); | 4219 FinalizeIncrementalMarking(gc_reason); |
| 4220 } else if (incremental_marking()->IsComplete() || | 4220 } else if (incremental_marking()->IsComplete() || |
| 4221 (mark_compact_collector()->marking_deque()->IsEmpty())) { | 4221 (mark_compact_collector()->marking_deque()->IsEmpty())) { |
| 4222 CollectAllGarbage(current_gc_flags_, comment); | 4222 CollectAllGarbage(current_gc_flags_, gc_reason); |
| 4223 } | 4223 } |
| 4224 } | 4224 } |
| 4225 | 4225 |
| 4226 | 4226 bool Heap::TryFinalizeIdleIncrementalMarking( |
| 4227 bool Heap::TryFinalizeIdleIncrementalMarking(double idle_time_in_ms) { | 4227 double idle_time_in_ms, GarbageCollectionReason gc_reason) { |
| 4228 size_t size_of_objects = static_cast<size_t>(SizeOfObjects()); | 4228 size_t size_of_objects = static_cast<size_t>(SizeOfObjects()); |
| 4229 double final_incremental_mark_compact_speed_in_bytes_per_ms = | 4229 double final_incremental_mark_compact_speed_in_bytes_per_ms = |
| 4230 tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond(); | 4230 tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond(); |
| 4231 if (incremental_marking()->IsReadyToOverApproximateWeakClosure() || | 4231 if (incremental_marking()->IsReadyToOverApproximateWeakClosure() || |
| 4232 (!incremental_marking()->finalize_marking_completed() && | 4232 (!incremental_marking()->finalize_marking_completed() && |
| 4233 MarkingDequesAreEmpty() && | 4233 MarkingDequesAreEmpty() && |
| 4234 gc_idle_time_handler_->ShouldDoOverApproximateWeakClosure( | 4234 gc_idle_time_handler_->ShouldDoOverApproximateWeakClosure( |
| 4235 idle_time_in_ms))) { | 4235 idle_time_in_ms))) { |
| 4236 FinalizeIncrementalMarking( | 4236 FinalizeIncrementalMarking(gc_reason); |
| 4237 "Idle notification: finalize incremental marking"); | |
| 4238 return true; | 4237 return true; |
| 4239 } else if (incremental_marking()->IsComplete() || | 4238 } else if (incremental_marking()->IsComplete() || |
| 4240 (MarkingDequesAreEmpty() && | 4239 (MarkingDequesAreEmpty() && |
| 4241 gc_idle_time_handler_->ShouldDoFinalIncrementalMarkCompact( | 4240 gc_idle_time_handler_->ShouldDoFinalIncrementalMarkCompact( |
| 4242 idle_time_in_ms, size_of_objects, | 4241 idle_time_in_ms, size_of_objects, |
| 4243 final_incremental_mark_compact_speed_in_bytes_per_ms))) { | 4242 final_incremental_mark_compact_speed_in_bytes_per_ms))) { |
| 4244 CollectAllGarbage(current_gc_flags_, | 4243 CollectAllGarbage(current_gc_flags_, gc_reason); |
| 4245 "idle notification: finalize incremental marking"); | |
| 4246 return true; | 4244 return true; |
| 4247 } | 4245 } |
| 4248 return false; | 4246 return false; |
| 4249 } | 4247 } |
| 4250 | 4248 |
| 4251 void Heap::RegisterReservationsForBlackAllocation(Reservation* reservations) { | 4249 void Heap::RegisterReservationsForBlackAllocation(Reservation* reservations) { |
| 4252 // TODO(hpayer): We do not have to iterate reservations on black objects | 4250 // TODO(hpayer): We do not have to iterate reservations on black objects |
| 4253 // for marking. We just have to execute the special visiting side effect | 4251 // for marking. We just have to execute the special visiting side effect |
| 4254 // code that adds objects to global data structures, e.g. for array buffers. | 4252 // code that adds objects to global data structures, e.g. for array buffers. |
| 4255 | 4253 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4310 ->NotifyIdleTaskProgress(); | 4308 ->NotifyIdleTaskProgress(); |
| 4311 result = IncrementalMarkingJob::IdleTask::Step(this, deadline_in_ms) == | 4309 result = IncrementalMarkingJob::IdleTask::Step(this, deadline_in_ms) == |
| 4312 IncrementalMarkingJob::IdleTask::kDone; | 4310 IncrementalMarkingJob::IdleTask::kDone; |
| 4313 } | 4311 } |
| 4314 break; | 4312 break; |
| 4315 } | 4313 } |
| 4316 case DO_FULL_GC: { | 4314 case DO_FULL_GC: { |
| 4317 DCHECK(contexts_disposed_ > 0); | 4315 DCHECK(contexts_disposed_ > 0); |
| 4318 HistogramTimerScope scope(isolate_->counters()->gc_context()); | 4316 HistogramTimerScope scope(isolate_->counters()->gc_context()); |
| 4319 TRACE_EVENT0("v8", "V8.GCContext"); | 4317 TRACE_EVENT0("v8", "V8.GCContext"); |
| 4320 CollectAllGarbage(kNoGCFlags, "idle notification: contexts disposed"); | 4318 CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal); |
| 4321 break; | 4319 break; |
| 4322 } | 4320 } |
| 4323 case DO_NOTHING: | 4321 case DO_NOTHING: |
| 4324 break; | 4322 break; |
| 4325 } | 4323 } |
| 4326 | 4324 |
| 4327 return result; | 4325 return result; |
| 4328 } | 4326 } |
| 4329 | 4327 |
| 4330 | 4328 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4443 | 4441 |
| 4444 void Heap::CheckMemoryPressure() { | 4442 void Heap::CheckMemoryPressure() { |
| 4445 if (HighMemoryPressure()) { | 4443 if (HighMemoryPressure()) { |
| 4446 if (isolate()->concurrent_recompilation_enabled()) { | 4444 if (isolate()->concurrent_recompilation_enabled()) { |
| 4447 // The optimizing compiler may be unnecessarily holding on to memory. | 4445 // The optimizing compiler may be unnecessarily holding on to memory. |
| 4448 DisallowHeapAllocation no_recursive_gc; | 4446 DisallowHeapAllocation no_recursive_gc; |
| 4449 isolate()->optimizing_compile_dispatcher()->Flush(); | 4447 isolate()->optimizing_compile_dispatcher()->Flush(); |
| 4450 } | 4448 } |
| 4451 } | 4449 } |
| 4452 if (memory_pressure_level_.Value() == MemoryPressureLevel::kCritical) { | 4450 if (memory_pressure_level_.Value() == MemoryPressureLevel::kCritical) { |
| 4453 CollectGarbageOnMemoryPressure("memory pressure"); | 4451 CollectGarbageOnMemoryPressure(); |
| 4454 } else if (memory_pressure_level_.Value() == MemoryPressureLevel::kModerate) { | 4452 } else if (memory_pressure_level_.Value() == MemoryPressureLevel::kModerate) { |
| 4455 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { | 4453 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { |
| 4456 StartIdleIncrementalMarking(); | 4454 StartIncrementalMarking(kReduceMemoryFootprintMask, |
| 4455 GarbageCollectionReason::kMemoryPressure); |
| 4457 } | 4456 } |
| 4458 } | 4457 } |
| 4459 MemoryReducer::Event event; | 4458 MemoryReducer::Event event; |
| 4460 event.type = MemoryReducer::kPossibleGarbage; | 4459 event.type = MemoryReducer::kPossibleGarbage; |
| 4461 event.time_ms = MonotonicallyIncreasingTimeInMs(); | 4460 event.time_ms = MonotonicallyIncreasingTimeInMs(); |
| 4462 memory_reducer_->NotifyPossibleGarbage(event); | 4461 memory_reducer_->NotifyPossibleGarbage(event); |
| 4463 } | 4462 } |
| 4464 | 4463 |
| 4465 void Heap::CollectGarbageOnMemoryPressure(const char* source) { | 4464 void Heap::CollectGarbageOnMemoryPressure() { |
| 4466 const int kGarbageThresholdInBytes = 8 * MB; | 4465 const int kGarbageThresholdInBytes = 8 * MB; |
| 4467 const double kGarbageThresholdAsFractionOfTotalMemory = 0.1; | 4466 const double kGarbageThresholdAsFractionOfTotalMemory = 0.1; |
| 4468 // This constant is the maximum response time in RAIL performance model. | 4467 // This constant is the maximum response time in RAIL performance model. |
| 4469 const double kMaxMemoryPressurePauseMs = 100; | 4468 const double kMaxMemoryPressurePauseMs = 100; |
| 4470 | 4469 |
| 4471 double start = MonotonicallyIncreasingTimeInMs(); | 4470 double start = MonotonicallyIncreasingTimeInMs(); |
| 4472 CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, | 4471 CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
| 4473 source, kGCCallbackFlagCollectAllAvailableGarbage); | 4472 GarbageCollectionReason::kMemoryPressure, |
| 4473 kGCCallbackFlagCollectAllAvailableGarbage); |
| 4474 double end = MonotonicallyIncreasingTimeInMs(); | 4474 double end = MonotonicallyIncreasingTimeInMs(); |
| 4475 | 4475 |
| 4476 // Estimate how much memory we can free. | 4476 // Estimate how much memory we can free. |
| 4477 int64_t potential_garbage = | 4477 int64_t potential_garbage = |
| 4478 (CommittedMemory() - SizeOfObjects()) + external_memory_; | 4478 (CommittedMemory() - SizeOfObjects()) + external_memory_; |
| 4479 // If we can potentially free large amount of memory, then start GC right | 4479 // If we can potentially free large amount of memory, then start GC right |
| 4480 // away instead of waiting for memory reducer. | 4480 // away instead of waiting for memory reducer. |
| 4481 if (potential_garbage >= kGarbageThresholdInBytes && | 4481 if (potential_garbage >= kGarbageThresholdInBytes && |
| 4482 potential_garbage >= | 4482 potential_garbage >= |
| 4483 CommittedMemory() * kGarbageThresholdAsFractionOfTotalMemory) { | 4483 CommittedMemory() * kGarbageThresholdAsFractionOfTotalMemory) { |
| 4484 // If we spent less than half of the time budget, then perform full GC | 4484 // If we spent less than half of the time budget, then perform full GC |
| 4485 // Otherwise, start incremental marking. | 4485 // Otherwise, start incremental marking. |
| 4486 if (end - start < kMaxMemoryPressurePauseMs / 2) { | 4486 if (end - start < kMaxMemoryPressurePauseMs / 2) { |
| 4487 CollectAllGarbage( | 4487 CollectAllGarbage( |
| 4488 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, source, | 4488 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, |
| 4489 GarbageCollectionReason::kMemoryPressure, |
| 4489 kGCCallbackFlagCollectAllAvailableGarbage); | 4490 kGCCallbackFlagCollectAllAvailableGarbage); |
| 4490 } else { | 4491 } else { |
| 4491 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { | 4492 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { |
| 4492 StartIdleIncrementalMarking(); | 4493 StartIncrementalMarking(kReduceMemoryFootprintMask, |
| 4494 GarbageCollectionReason::kMemoryPressure); |
| 4493 } | 4495 } |
| 4494 } | 4496 } |
| 4495 } | 4497 } |
| 4496 } | 4498 } |
| 4497 | 4499 |
| 4498 void Heap::MemoryPressureNotification(MemoryPressureLevel level, | 4500 void Heap::MemoryPressureNotification(MemoryPressureLevel level, |
| 4499 bool is_isolate_locked) { | 4501 bool is_isolate_locked) { |
| 4500 MemoryPressureLevel previous = memory_pressure_level_.Value(); | 4502 MemoryPressureLevel previous = memory_pressure_level_.Value(); |
| 4501 memory_pressure_level_.SetValue(level); | 4503 memory_pressure_level_.SetValue(level); |
| 4502 if ((previous != MemoryPressureLevel::kCritical && | 4504 if ((previous != MemoryPressureLevel::kCritical && |
| (...skipping 1972 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6475 } | 6477 } |
| 6476 | 6478 |
| 6477 | 6479 |
| 6478 // static | 6480 // static |
| 6479 int Heap::GetStaticVisitorIdForMap(Map* map) { | 6481 int Heap::GetStaticVisitorIdForMap(Map* map) { |
| 6480 return StaticVisitorBase::GetVisitorId(map); | 6482 return StaticVisitorBase::GetVisitorId(map); |
| 6481 } | 6483 } |
| 6482 | 6484 |
| 6483 } // namespace internal | 6485 } // namespace internal |
| 6484 } // namespace v8 | 6486 } // namespace v8 |
| OLD | NEW |