Chromium Code Reviews| 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 |