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/v8.h" | 5 #include "src/v8.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/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 1200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1211 // We speed up the incremental marker if it is running so that it | 1211 // We speed up the incremental marker if it is running so that it |
1212 // does not fall behind the rate of promotion, which would cause a | 1212 // does not fall behind the rate of promotion, which would cause a |
1213 // constantly growing old space. | 1213 // constantly growing old space. |
1214 incremental_marking()->NotifyOfHighPromotionRate(); | 1214 incremental_marking()->NotifyOfHighPromotionRate(); |
1215 } | 1215 } |
1216 | 1216 |
1217 if (collector == MARK_COMPACTOR) { | 1217 if (collector == MARK_COMPACTOR) { |
1218 // Perform mark-sweep with optional compaction. | 1218 // Perform mark-sweep with optional compaction. |
1219 MarkCompact(); | 1219 MarkCompact(); |
1220 sweep_generation_++; | 1220 sweep_generation_++; |
1221 // Temporarily set the limit for case when PostGarbageCollectionProcessing | |
1222 // allocates and triggers GC. The real limit is set at after | |
1223 // PostGarbageCollectionProcessing. | |
1224 const double kConservativeFactor = 1.5; | |
1225 SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), | |
1226 kConservativeFactor); | |
1221 old_gen_exhausted_ = false; | 1227 old_gen_exhausted_ = false; |
1222 old_generation_size_configured_ = true; | 1228 old_generation_size_configured_ = true; |
1223 } else { | 1229 } else { |
1224 Scavenge(); | 1230 Scavenge(); |
1225 } | 1231 } |
1226 | 1232 |
1227 // This should be updated before PostGarbageCollectionProcessing, which can | 1233 // This should be updated before PostGarbageCollectionProcessing, which can |
1228 // cause another GC. | 1234 // cause another GC. |
1229 old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects(); | 1235 old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects(); |
1230 | 1236 |
(...skipping 13 matching lines...) Expand all Loading... | |
1244 freed_global_handles = | 1250 freed_global_handles = |
1245 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); | 1251 isolate_->global_handles()->PostGarbageCollectionProcessing(collector); |
1246 } | 1252 } |
1247 gc_post_processing_depth_--; | 1253 gc_post_processing_depth_--; |
1248 | 1254 |
1249 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); | 1255 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); |
1250 | 1256 |
1251 // Update relocatables. | 1257 // Update relocatables. |
1252 Relocatable::PostGarbageCollectionProcessing(isolate_); | 1258 Relocatable::PostGarbageCollectionProcessing(isolate_); |
1253 | 1259 |
1260 int fragmentation_percent = 0; | |
1261 | |
1254 if (collector == MARK_COMPACTOR) { | 1262 if (collector == MARK_COMPACTOR) { |
1255 // Register the amount of external allocated memory. | 1263 // Register the amount of external allocated memory. |
1256 amount_of_external_allocated_memory_at_last_global_gc_ = | 1264 amount_of_external_allocated_memory_at_last_global_gc_ = |
1257 amount_of_external_allocated_memory_; | 1265 amount_of_external_allocated_memory_; |
1258 SetOldGenerationAllocationLimit( | 1266 double factor = HeapGrowingFactor( |
1259 PromotedSpaceSizeOfObjects(), | 1267 freed_global_handles, |
1260 tracer()->CurrentAllocationThroughputInBytesPerMillisecond()); | 1268 tracer()->CurrentAllocationThroughputInBytesPerMillisecond(), |
1269 FragmentationOfCompactedSpacesInPercent()); | |
1270 SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), factor); | |
1261 // We finished a marking cycle. We can uncommit the marking deque until | 1271 // We finished a marking cycle. We can uncommit the marking deque until |
1262 // we start marking again. | 1272 // we start marking again. |
1263 mark_compact_collector_.UncommitMarkingDeque(); | 1273 mark_compact_collector_.UncommitMarkingDeque(); |
1264 } | 1274 } |
1265 | 1275 |
1266 { | 1276 { |
1267 GCCallbacksScope scope(this); | 1277 GCCallbacksScope scope(this); |
1268 if (scope.CheckReenter()) { | 1278 if (scope.CheckReenter()) { |
1269 AllowHeapAllocation allow_allocation; | 1279 AllowHeapAllocation allow_allocation; |
1270 GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); | 1280 GCTracer::Scope scope(tracer(), GCTracer::Scope::EXTERNAL); |
1271 VMState<EXTERNAL> state(isolate_); | 1281 VMState<EXTERNAL> state(isolate_); |
1272 HandleScope handle_scope(isolate_); | 1282 HandleScope handle_scope(isolate_); |
1273 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); | 1283 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); |
1274 } | 1284 } |
1275 } | 1285 } |
1276 | 1286 |
1277 #ifdef VERIFY_HEAP | 1287 #ifdef VERIFY_HEAP |
1278 if (FLAG_verify_heap) { | 1288 if (FLAG_verify_heap) { |
1279 VerifyStringTable(this); | 1289 VerifyStringTable(this); |
1280 } | 1290 } |
1281 #endif | 1291 #endif |
1282 | 1292 |
1283 return freed_global_handles > 0; | 1293 return freed_global_handles > 0 || |
1294 fragmentation_percent >= kLowFragmentationPercent; | |
Hannes Payer (out of office)
2015/06/02 08:23:00
Can we move this code into a function with a descr
ulan
2015/06/02 12:27:05
Done.
| |
1284 } | 1295 } |
1285 | 1296 |
1286 | 1297 |
1287 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { | 1298 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { |
1288 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 1299 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { |
1289 if (gc_type & gc_prologue_callbacks_[i].gc_type) { | 1300 if (gc_type & gc_prologue_callbacks_[i].gc_type) { |
1290 if (!gc_prologue_callbacks_[i].pass_isolate_) { | 1301 if (!gc_prologue_callbacks_[i].pass_isolate_) { |
1291 v8::GCPrologueCallback callback = | 1302 v8::GCPrologueCallback callback = |
1292 reinterpret_cast<v8::GCPrologueCallback>( | 1303 reinterpret_cast<v8::GCPrologueCallback>( |
1293 gc_prologue_callbacks_[i].callback); | 1304 gc_prologue_callbacks_[i].callback); |
(...skipping 4089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5383 CHECK(factor > 1.0); | 5394 CHECK(factor > 1.0); |
5384 CHECK(old_gen_size > 0); | 5395 CHECK(old_gen_size > 0); |
5385 intptr_t limit = static_cast<intptr_t>(old_gen_size * factor); | 5396 intptr_t limit = static_cast<intptr_t>(old_gen_size * factor); |
5386 limit = Max(limit, old_gen_size + kMinimumOldGenerationAllocationLimit); | 5397 limit = Max(limit, old_gen_size + kMinimumOldGenerationAllocationLimit); |
5387 limit += new_space_.Capacity(); | 5398 limit += new_space_.Capacity(); |
5388 intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; | 5399 intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; |
5389 return Min(limit, halfway_to_the_max); | 5400 return Min(limit, halfway_to_the_max); |
5390 } | 5401 } |
5391 | 5402 |
5392 | 5403 |
5393 void Heap::SetOldGenerationAllocationLimit( | 5404 double LinearInterpolation(double x1, double y1, double x2, double y2, |
5394 intptr_t old_gen_size, size_t current_allocation_throughput) { | 5405 double x) { |
5406 DCHECK(x1 < x2); | |
5407 if (x <= x1) return y1; | |
5408 if (x >= x2) return y2; | |
5409 return y1 + (y2 - y1) / (x2 - x1) * (x - x1); | |
5410 } | |
5411 | |
5412 | |
5413 double Heap::HeapGrowingFactor(int freed_handles, size_t allocation_throughput, | |
5414 int fragmentation_percent) { | |
5415 const int kLowHandles = 100; | |
5416 const int kHighHandles = 1000; | |
5395 // Allocation throughput on Android devices is typically lower than on | 5417 // Allocation throughput on Android devices is typically lower than on |
5396 // non-mobile devices. | 5418 // non-mobile devices. |
5397 #if V8_OS_ANDROID | 5419 #if V8_OS_ANDROID |
5398 const size_t kHighThroughput = 2500; | 5420 const size_t kHighThroughput = 2500; |
5399 const size_t kLowThroughput = 250; | 5421 const size_t kLowThroughput = 250; |
5400 #else | 5422 #else |
5401 const size_t kHighThroughput = 10000; | 5423 const size_t kHighThroughput = 10000; |
5402 const size_t kLowThroughput = 1000; | 5424 const size_t kLowThroughput = 1000; |
5403 #endif | 5425 #endif |
5404 const double min_scaling_factor = 1.1; | 5426 const double min_factor = 1.1; |
5405 const double max_scaling_factor = 1.5; | 5427 const double max_factor = 1.5; |
5406 double max_factor = 4; | 5428 if (allocation_throughput == 0) { |
5407 const double idle_max_factor = 1.5; | 5429 // If we have no allocation throughput estimate, we conservatively assume |
5408 // We set the old generation growing factor to 2 to grow the heap slower on | 5430 // that it is high. |
5409 // memory-constrained devices. | 5431 allocation_throughput = kHighThroughput; |
5410 if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { | |
5411 max_factor = 2; | |
5412 } | 5432 } |
5433 double factor1 = LinearInterpolation(kLowHandles, max_factor, kHighHandles, | |
5434 min_factor, freed_handles); | |
5435 double factor2 = | |
5436 LinearInterpolation(kLowThroughput, min_factor, kHighThroughput, | |
5437 max_factor, allocation_throughput); | |
5438 double factor3 = LinearInterpolation(kLowFragmentationPercent, max_factor, | |
5439 kHighFragmentationPercent, min_factor, | |
5440 fragmentation_percent); | |
5413 | 5441 |
5414 double factor; | 5442 double factor = Min(factor1, factor2); |
5415 double idle_factor; | 5443 if (factor >= max_factor) { |
5416 if (current_allocation_throughput == 0 || | 5444 // We need high throughput, schedule GC late. |
5417 current_allocation_throughput >= kHighThroughput) { | 5445 // We set the old generation growing factor to 2 to grow the heap slower on |
5418 factor = max_factor; | 5446 // memory-constrained devices. |
5419 } else if (current_allocation_throughput <= kLowThroughput) { | 5447 factor = (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) |
5420 factor = min_scaling_factor; | 5448 ? 2 |
Hannes Payer (out of office)
2015/06/02 08:23:00
Let's make these two value also constants.
ulan
2015/06/02 12:27:05
Done.
| |
5449 : 4; | |
5421 } else { | 5450 } else { |
5422 // Compute factor using linear interpolation between points | 5451 factor = Min(factor, factor3); |
5423 // (kHighThroughput, max_scaling_factor) and (kLowThroughput, min_factor). | |
5424 factor = min_scaling_factor + | |
5425 (current_allocation_throughput - kLowThroughput) * | |
5426 (max_scaling_factor - min_scaling_factor) / | |
5427 (kHighThroughput - kLowThroughput); | |
5428 } | 5452 } |
5429 | 5453 |
5430 if (FLAG_stress_compaction || | 5454 if (FLAG_stress_compaction || |
5431 mark_compact_collector()->reduce_memory_footprint_) { | 5455 mark_compact_collector()->reduce_memory_footprint_) { |
5432 factor = min_scaling_factor; | 5456 factor = min_factor; |
5433 } | 5457 } |
5434 | 5458 |
5459 if (FLAG_trace_gc_verbose) { | |
5460 PrintIsolate(isolate_, | |
5461 "Freed handles: %d (factor %.1f)," | |
5462 "allocation throughput: %u (factor %.1f)," | |
5463 "fragmentation: %d (factor %.1f), combined factor: %.1f\n", | |
5464 freed_handles, factor1, allocation_throughput, factor2, | |
5465 fragmentation_percent, factor3); | |
5466 } | |
5467 return factor; | |
5468 } | |
5469 | |
5470 | |
5471 void Heap::SetOldGenerationAllocationLimit(intptr_t old_gen_size, | |
5472 double factor) { | |
5473 const double idle_max_factor = 1.5; | |
5474 | |
5435 // TODO(hpayer): Investigate if idle_old_generation_allocation_limit_ is still | 5475 // TODO(hpayer): Investigate if idle_old_generation_allocation_limit_ is still |
5436 // needed after taking the allocation rate for the old generation limit into | 5476 // needed after taking the allocation rate for the old generation limit into |
5437 // account. | 5477 // account. |
5438 idle_factor = Min(factor, idle_max_factor); | 5478 const double idle_factor = Min(factor, idle_max_factor); |
5439 | 5479 |
5440 old_generation_allocation_limit_ = | 5480 old_generation_allocation_limit_ = |
5441 CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5481 CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
5442 idle_old_generation_allocation_limit_ = | 5482 idle_old_generation_allocation_limit_ = |
5443 CalculateOldGenerationAllocationLimit(idle_factor, old_gen_size); | 5483 CalculateOldGenerationAllocationLimit(idle_factor, old_gen_size); |
5444 | 5484 |
5445 if (FLAG_trace_gc_verbose) { | 5485 if (FLAG_trace_gc_verbose) { |
5446 PrintIsolate( | 5486 PrintIsolate( |
5447 isolate_, | 5487 isolate_, |
5448 "Grow: old size: %" V8_PTR_PREFIX "d KB, new limit: %" V8_PTR_PREFIX | 5488 "Grow: old size: %" V8_PTR_PREFIX "d KB, new limit: %" V8_PTR_PREFIX |
(...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6665 *object_type = "CODE_TYPE"; \ | 6705 *object_type = "CODE_TYPE"; \ |
6666 *object_sub_type = "CODE_AGE/" #name; \ | 6706 *object_sub_type = "CODE_AGE/" #name; \ |
6667 return true; | 6707 return true; |
6668 CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME) | 6708 CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME) |
6669 #undef COMPARE_AND_RETURN_NAME | 6709 #undef COMPARE_AND_RETURN_NAME |
6670 } | 6710 } |
6671 return false; | 6711 return false; |
6672 } | 6712 } |
6673 } | 6713 } |
6674 } // namespace v8::internal | 6714 } // namespace v8::internal |
OLD | NEW |