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 <unordered_map> | 7 #include <unordered_map> |
8 #include <unordered_set> | 8 #include <unordered_set> |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 4175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4186 bool Heap::HasHighFragmentation(size_t used, size_t committed) { | 4186 bool Heap::HasHighFragmentation(size_t used, size_t committed) { |
4187 const size_t kSlack = 16 * MB; | 4187 const size_t kSlack = 16 * MB; |
4188 // Fragmentation is high if committed > 2 * used + kSlack. | 4188 // Fragmentation is high if committed > 2 * used + kSlack. |
4189 // Rewrite the exression to avoid overflow. | 4189 // Rewrite the exression to avoid overflow. |
4190 DCHECK_GE(committed, used); | 4190 DCHECK_GE(committed, used); |
4191 return committed - used > used + kSlack; | 4191 return committed - used > used + kSlack; |
4192 } | 4192 } |
4193 | 4193 |
4194 bool Heap::ShouldOptimizeForMemoryUsage() { | 4194 bool Heap::ShouldOptimizeForMemoryUsage() { |
4195 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || | 4195 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || |
4196 HighMemoryPressure() || IsLowMemoryDevice(); | 4196 HighMemoryPressure(); |
4197 } | 4197 } |
4198 | 4198 |
4199 void Heap::ActivateMemoryReducerIfNeeded() { | 4199 void Heap::ActivateMemoryReducerIfNeeded() { |
4200 // Activate memory reducer when switching to background if | 4200 // Activate memory reducer when switching to background if |
4201 // - there was no mark compact since the start. | 4201 // - there was no mark compact since the start. |
4202 // - the committed memory can be potentially reduced. | 4202 // - the committed memory can be potentially reduced. |
4203 // 2 pages for the old, code, and map space + 1 page for new space. | 4203 // 2 pages for the old, code, and map space + 1 page for new space. |
4204 const int kMinCommittedMemory = 7 * Page::kPageSize; | 4204 const int kMinCommittedMemory = 7 * Page::kPageSize; |
4205 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && | 4205 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && |
4206 isolate()->IsIsolateInBackground()) { | 4206 isolate()->IsIsolateInBackground()) { |
(...skipping 1217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5424 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) | 5424 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) |
5425 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) | 5425 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) |
5426 // substitute R = gc_speed / mutator_speed | 5426 // substitute R = gc_speed / mutator_speed |
5427 // (Limit - Live) = Limit * MU / (R * (1 - MU)) | 5427 // (Limit - Live) = Limit * MU / (R * (1 - MU)) |
5428 // substitute F = Limit / Live | 5428 // substitute F = Limit / Live |
5429 // F - 1 = F * MU / (R * (1 - MU)) | 5429 // F - 1 = F * MU / (R * (1 - MU)) |
5430 // F - F * MU / (R * (1 - MU)) = 1 | 5430 // F - F * MU / (R * (1 - MU)) = 1 |
5431 // F * (1 - MU / (R * (1 - MU))) = 1 | 5431 // F * (1 - MU / (R * (1 - MU))) = 1 |
5432 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 | 5432 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 |
5433 // F = R * (1 - MU) / (R * (1 - MU) - MU) | 5433 // F = R * (1 - MU) / (R * (1 - MU) - MU) |
5434 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed) { | 5434 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed, |
5435 if (gc_speed == 0 || mutator_speed == 0) return kMaxHeapGrowingFactor; | 5435 double max_factor) { |
5436 DCHECK(max_factor >= kMinHeapGrowingFactor); | |
5437 DCHECK(max_factor <= kMaxHeapGrowingFactor); | |
5438 if (gc_speed == 0 || mutator_speed == 0) return max_factor; | |
5436 | 5439 |
5437 const double speed_ratio = gc_speed / mutator_speed; | 5440 const double speed_ratio = gc_speed / mutator_speed; |
5438 const double mu = kTargetMutatorUtilization; | 5441 const double mu = kTargetMutatorUtilization; |
5439 | 5442 |
5440 const double a = speed_ratio * (1 - mu); | 5443 const double a = speed_ratio * (1 - mu); |
5441 const double b = speed_ratio * (1 - mu) - mu; | 5444 const double b = speed_ratio * (1 - mu) - mu; |
5442 | 5445 |
5443 // The factor is a / b, but we need to check for small b first. | 5446 // The factor is a / b, but we need to check for small b first. |
5444 double factor = | 5447 double factor = (a < b * max_factor) ? a / b : max_factor; |
5445 (a < b * kMaxHeapGrowingFactor) ? a / b : kMaxHeapGrowingFactor; | 5448 factor = Min(factor, max_factor); |
5446 factor = Min(factor, kMaxHeapGrowingFactor); | |
5447 factor = Max(factor, kMinHeapGrowingFactor); | 5449 factor = Max(factor, kMinHeapGrowingFactor); |
5448 return factor; | 5450 return factor; |
5449 } | 5451 } |
5450 | 5452 |
5453 double Heap::MaxHeapGrowingFactor(size_t max_old_generation_size) { | |
5454 const double min_small_factor = 1.3; | |
5455 const double max_small_factor = 2.0; | |
5456 const double high_factor = 4.0; | |
5457 | |
5458 size_t max_old_generation_size_in_mb = max_old_generation_size / MB; | |
5459 max_old_generation_size_in_mb = | |
5460 Max(max_old_generation_size_in_mb, | |
5461 static_cast<size_t>(kMinOldGenerationSize)); | |
5462 | |
5463 // If we are on a device with lots of memory, we allow a high heap | |
5464 // growing factor. | |
5465 if (max_old_generation_size_in_mb == kMaxOldGenerationSize) { | |
ulan
2017/06/09 08:39:43
Should it be >= instead of == ?
Hannes Payer (out of office)
2017/06/09 12:16:47
Done.
| |
5466 return high_factor; | |
5467 } | |
5468 | |
5469 DCHECK_GE(max_old_generation_size_in_mb, kMinOldGenerationSize); | |
5470 DCHECK_LT(max_old_generation_size_in_mb, kMaxOldGenerationSize); | |
5471 | |
5472 // On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C | |
5473 double factor = (max_old_generation_size_in_mb - kMinOldGenerationSize) * | |
5474 (max_small_factor - min_small_factor) / | |
5475 (kMaxOldGenerationSize - 1 - kMinOldGenerationSize) + | |
ulan
2017/06/09 08:39:43
Why (-1) here?
Hannes Payer (out of office)
2017/06/09 12:16:47
I decided to do that because we would never reach
| |
5476 min_small_factor; | |
5477 return factor; | |
5478 } | |
5479 | |
5451 size_t Heap::CalculateOldGenerationAllocationLimit(double factor, | 5480 size_t Heap::CalculateOldGenerationAllocationLimit(double factor, |
5452 size_t old_gen_size) { | 5481 size_t old_gen_size) { |
5453 CHECK(factor > 1.0); | 5482 CHECK(factor > 1.0); |
5454 CHECK(old_gen_size > 0); | 5483 CHECK(old_gen_size > 0); |
5455 uint64_t limit = static_cast<uint64_t>(old_gen_size * factor); | 5484 uint64_t limit = static_cast<uint64_t>(old_gen_size * factor); |
5456 limit = Max(limit, static_cast<uint64_t>(old_gen_size) + | 5485 limit = Max(limit, static_cast<uint64_t>(old_gen_size) + |
5457 MinimumAllocationLimitGrowingStep()); | 5486 MinimumAllocationLimitGrowingStep()); |
5458 limit += new_space_->Capacity(); | 5487 limit += new_space_->Capacity(); |
5459 uint64_t halfway_to_the_max = | 5488 uint64_t halfway_to_the_max = |
5460 (static_cast<uint64_t>(old_gen_size) + max_old_generation_size_) / 2; | 5489 (static_cast<uint64_t>(old_gen_size) + max_old_generation_size_) / 2; |
5461 return static_cast<size_t>(Min(limit, halfway_to_the_max)); | 5490 return static_cast<size_t>(Min(limit, halfway_to_the_max)); |
5462 } | 5491 } |
5463 | 5492 |
5464 size_t Heap::MinimumAllocationLimitGrowingStep() { | 5493 size_t Heap::MinimumAllocationLimitGrowingStep() { |
5465 const size_t kRegularAllocationLimitGrowingStep = 8; | 5494 const size_t kRegularAllocationLimitGrowingStep = 8; |
5466 const size_t kLowMemoryAllocationLimitGrowingStep = 2; | 5495 const size_t kLowMemoryAllocationLimitGrowingStep = 2; |
5467 size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB); | 5496 size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB); |
5468 return limit * (ShouldOptimizeForMemoryUsage() | 5497 return limit * (ShouldOptimizeForMemoryUsage() |
5469 ? kLowMemoryAllocationLimitGrowingStep | 5498 ? kLowMemoryAllocationLimitGrowingStep |
5470 : kRegularAllocationLimitGrowingStep); | 5499 : kRegularAllocationLimitGrowingStep); |
5471 } | 5500 } |
5472 | 5501 |
5473 void Heap::SetOldGenerationAllocationLimit(size_t old_gen_size, double gc_speed, | 5502 void Heap::SetOldGenerationAllocationLimit(size_t old_gen_size, double gc_speed, |
5474 double mutator_speed) { | 5503 double mutator_speed) { |
5475 double factor = HeapGrowingFactor(gc_speed, mutator_speed); | 5504 double max_factor = MaxHeapGrowingFactor(max_old_generation_size_); |
5505 double factor = HeapGrowingFactor(gc_speed, mutator_speed, max_factor); | |
5476 | 5506 |
5477 if (FLAG_trace_gc_verbose) { | 5507 if (FLAG_trace_gc_verbose) { |
5478 isolate_->PrintWithTimestamp( | 5508 isolate_->PrintWithTimestamp( |
5479 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " | 5509 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " |
5480 "(gc=%.f, mutator=%.f)\n", | 5510 "(gc=%.f, mutator=%.f)\n", |
5481 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, gc_speed, | 5511 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, gc_speed, |
5482 mutator_speed); | 5512 mutator_speed); |
5483 } | 5513 } |
5484 | 5514 |
5485 if (IsMemoryConstrainedDevice()) { | |
5486 factor = Min(factor, kMaxHeapGrowingFactorMemoryConstrained); | |
5487 } | |
5488 | |
5489 if (memory_reducer_->ShouldGrowHeapSlowly() || | 5515 if (memory_reducer_->ShouldGrowHeapSlowly() || |
5490 ShouldOptimizeForMemoryUsage()) { | 5516 ShouldOptimizeForMemoryUsage()) { |
5491 factor = Min(factor, kConservativeHeapGrowingFactor); | 5517 factor = Min(factor, kConservativeHeapGrowingFactor); |
5492 } | 5518 } |
5493 | 5519 |
5494 if (FLAG_stress_compaction || ShouldReduceMemory()) { | 5520 if (FLAG_stress_compaction || ShouldReduceMemory()) { |
5495 factor = kMinHeapGrowingFactor; | 5521 factor = kMinHeapGrowingFactor; |
5496 } | 5522 } |
5497 | 5523 |
5498 if (FLAG_heap_growing_percent > 0) { | 5524 if (FLAG_heap_growing_percent > 0) { |
5499 factor = 1.0 + FLAG_heap_growing_percent / 100.0; | 5525 factor = 1.0 + FLAG_heap_growing_percent / 100.0; |
5500 } | 5526 } |
5501 | 5527 |
5502 old_generation_allocation_limit_ = | 5528 old_generation_allocation_limit_ = |
5503 CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5529 CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
5504 | 5530 |
5505 if (FLAG_trace_gc_verbose) { | 5531 if (FLAG_trace_gc_verbose) { |
5506 isolate_->PrintWithTimestamp( | 5532 isolate_->PrintWithTimestamp( |
5507 "Grow: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n", | 5533 "Grow: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n", |
5508 old_gen_size / KB, old_generation_allocation_limit_ / KB, factor); | 5534 old_gen_size / KB, old_generation_allocation_limit_ / KB, factor); |
5509 } | 5535 } |
5510 } | 5536 } |
5511 | 5537 |
5512 void Heap::DampenOldGenerationAllocationLimit(size_t old_gen_size, | 5538 void Heap::DampenOldGenerationAllocationLimit(size_t old_gen_size, |
5513 double gc_speed, | 5539 double gc_speed, |
5514 double mutator_speed) { | 5540 double mutator_speed) { |
5515 double factor = HeapGrowingFactor(gc_speed, mutator_speed); | 5541 double max_factor = MaxHeapGrowingFactor(max_old_generation_size_); |
5542 double factor = HeapGrowingFactor(gc_speed, mutator_speed, max_factor); | |
5516 size_t limit = CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5543 size_t limit = CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
5517 if (limit < old_generation_allocation_limit_) { | 5544 if (limit < old_generation_allocation_limit_) { |
5518 if (FLAG_trace_gc_verbose) { | 5545 if (FLAG_trace_gc_verbose) { |
5519 isolate_->PrintWithTimestamp( | 5546 isolate_->PrintWithTimestamp( |
5520 "Dampen: old size: %" PRIuS " KB, old limit: %" PRIuS | 5547 "Dampen: old size: %" PRIuS " KB, old limit: %" PRIuS |
5521 " KB, " | 5548 " KB, " |
5522 "new limit: %" PRIuS " KB (%.1f)\n", | 5549 "new limit: %" PRIuS " KB (%.1f)\n", |
5523 old_gen_size / KB, old_generation_allocation_limit_ / KB, limit / KB, | 5550 old_gen_size / KB, old_generation_allocation_limit_ / KB, limit / KB, |
5524 factor); | 5551 factor); |
5525 } | 5552 } |
(...skipping 1081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6607 case LO_SPACE: | 6634 case LO_SPACE: |
6608 return "LO_SPACE"; | 6635 return "LO_SPACE"; |
6609 default: | 6636 default: |
6610 UNREACHABLE(); | 6637 UNREACHABLE(); |
6611 } | 6638 } |
6612 return NULL; | 6639 return NULL; |
6613 } | 6640 } |
6614 | 6641 |
6615 } // namespace internal | 6642 } // namespace internal |
6616 } // namespace v8 | 6643 } // namespace v8 |
OLD | NEW |