| 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 4166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4177 bool Heap::HasHighFragmentation(size_t used, size_t committed) { | 4177 bool Heap::HasHighFragmentation(size_t used, size_t committed) { |
| 4178 const size_t kSlack = 16 * MB; | 4178 const size_t kSlack = 16 * MB; |
| 4179 // Fragmentation is high if committed > 2 * used + kSlack. | 4179 // Fragmentation is high if committed > 2 * used + kSlack. |
| 4180 // Rewrite the exression to avoid overflow. | 4180 // Rewrite the exression to avoid overflow. |
| 4181 DCHECK_GE(committed, used); | 4181 DCHECK_GE(committed, used); |
| 4182 return committed - used > used + kSlack; | 4182 return committed - used > used + kSlack; |
| 4183 } | 4183 } |
| 4184 | 4184 |
| 4185 bool Heap::ShouldOptimizeForMemoryUsage() { | 4185 bool Heap::ShouldOptimizeForMemoryUsage() { |
| 4186 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || | 4186 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || |
| 4187 HighMemoryPressure() || IsLowMemoryDevice(); | 4187 HighMemoryPressure(); |
| 4188 } | 4188 } |
| 4189 | 4189 |
| 4190 void Heap::ActivateMemoryReducerIfNeeded() { | 4190 void Heap::ActivateMemoryReducerIfNeeded() { |
| 4191 // Activate memory reducer when switching to background if | 4191 // Activate memory reducer when switching to background if |
| 4192 // - there was no mark compact since the start. | 4192 // - there was no mark compact since the start. |
| 4193 // - the committed memory can be potentially reduced. | 4193 // - the committed memory can be potentially reduced. |
| 4194 // 2 pages for the old, code, and map space + 1 page for new space. | 4194 // 2 pages for the old, code, and map space + 1 page for new space. |
| 4195 const int kMinCommittedMemory = 7 * Page::kPageSize; | 4195 const int kMinCommittedMemory = 7 * Page::kPageSize; |
| 4196 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && | 4196 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && |
| 4197 isolate()->IsIsolateInBackground()) { | 4197 isolate()->IsIsolateInBackground()) { |
| (...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5417 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) | 5417 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) |
| 5418 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) | 5418 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) |
| 5419 // substitute R = gc_speed / mutator_speed | 5419 // substitute R = gc_speed / mutator_speed |
| 5420 // (Limit - Live) = Limit * MU / (R * (1 - MU)) | 5420 // (Limit - Live) = Limit * MU / (R * (1 - MU)) |
| 5421 // substitute F = Limit / Live | 5421 // substitute F = Limit / Live |
| 5422 // F - 1 = F * MU / (R * (1 - MU)) | 5422 // F - 1 = F * MU / (R * (1 - MU)) |
| 5423 // F - F * MU / (R * (1 - MU)) = 1 | 5423 // F - F * MU / (R * (1 - MU)) = 1 |
| 5424 // F * (1 - MU / (R * (1 - MU))) = 1 | 5424 // F * (1 - MU / (R * (1 - MU))) = 1 |
| 5425 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 | 5425 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 |
| 5426 // F = R * (1 - MU) / (R * (1 - MU) - MU) | 5426 // F = R * (1 - MU) / (R * (1 - MU) - MU) |
| 5427 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed) { | 5427 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed, |
| 5428 if (gc_speed == 0 || mutator_speed == 0) return kMaxHeapGrowingFactor; | 5428 double max_factor) { |
| 5429 DCHECK(max_factor >= kMinHeapGrowingFactor); |
| 5430 DCHECK(max_factor <= kMaxHeapGrowingFactor); |
| 5431 if (gc_speed == 0 || mutator_speed == 0) return max_factor; |
| 5429 | 5432 |
| 5430 const double speed_ratio = gc_speed / mutator_speed; | 5433 const double speed_ratio = gc_speed / mutator_speed; |
| 5431 const double mu = kTargetMutatorUtilization; | 5434 const double mu = kTargetMutatorUtilization; |
| 5432 | 5435 |
| 5433 const double a = speed_ratio * (1 - mu); | 5436 const double a = speed_ratio * (1 - mu); |
| 5434 const double b = speed_ratio * (1 - mu) - mu; | 5437 const double b = speed_ratio * (1 - mu) - mu; |
| 5435 | 5438 |
| 5436 // The factor is a / b, but we need to check for small b first. | 5439 // The factor is a / b, but we need to check for small b first. |
| 5437 double factor = | 5440 double factor = (a < b * max_factor) ? a / b : max_factor; |
| 5438 (a < b * kMaxHeapGrowingFactor) ? a / b : kMaxHeapGrowingFactor; | 5441 factor = Min(factor, max_factor); |
| 5439 factor = Min(factor, kMaxHeapGrowingFactor); | |
| 5440 factor = Max(factor, kMinHeapGrowingFactor); | 5442 factor = Max(factor, kMinHeapGrowingFactor); |
| 5441 return factor; | 5443 return factor; |
| 5442 } | 5444 } |
| 5443 | 5445 |
| 5446 double Heap::MaxHeapGrowingFactor(size_t max_old_generation_size) { |
| 5447 const double min_small_factor = 1.3; |
| 5448 const double max_small_factor = 2.0; |
| 5449 const double high_factor = 4.0; |
| 5450 |
| 5451 size_t max_old_generation_size_in_mb = max_old_generation_size / MB; |
| 5452 max_old_generation_size_in_mb = |
| 5453 Max(max_old_generation_size_in_mb, |
| 5454 static_cast<size_t>(kMinOldGenerationSize)); |
| 5455 |
| 5456 // If we are on a device with lots of memory, we allow a high heap |
| 5457 // growing factor. |
| 5458 if (max_old_generation_size_in_mb >= kMaxOldGenerationSize) { |
| 5459 return high_factor; |
| 5460 } |
| 5461 |
| 5462 DCHECK_GE(max_old_generation_size_in_mb, kMinOldGenerationSize); |
| 5463 DCHECK_LT(max_old_generation_size_in_mb, kMaxOldGenerationSize); |
| 5464 |
| 5465 // On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C |
| 5466 double factor = (max_old_generation_size_in_mb - kMinOldGenerationSize) * |
| 5467 (max_small_factor - min_small_factor) / |
| 5468 (kMaxOldGenerationSize - kMinOldGenerationSize) + |
| 5469 min_small_factor; |
| 5470 return factor; |
| 5471 } |
| 5472 |
| 5444 size_t Heap::CalculateOldGenerationAllocationLimit(double factor, | 5473 size_t Heap::CalculateOldGenerationAllocationLimit(double factor, |
| 5445 size_t old_gen_size) { | 5474 size_t old_gen_size) { |
| 5446 CHECK(factor > 1.0); | 5475 CHECK(factor > 1.0); |
| 5447 CHECK(old_gen_size > 0); | 5476 CHECK(old_gen_size > 0); |
| 5448 uint64_t limit = static_cast<uint64_t>(old_gen_size * factor); | 5477 uint64_t limit = static_cast<uint64_t>(old_gen_size * factor); |
| 5449 limit = Max(limit, static_cast<uint64_t>(old_gen_size) + | 5478 limit = Max(limit, static_cast<uint64_t>(old_gen_size) + |
| 5450 MinimumAllocationLimitGrowingStep()); | 5479 MinimumAllocationLimitGrowingStep()); |
| 5451 limit += new_space_->Capacity(); | 5480 limit += new_space_->Capacity(); |
| 5452 uint64_t halfway_to_the_max = | 5481 uint64_t halfway_to_the_max = |
| 5453 (static_cast<uint64_t>(old_gen_size) + max_old_generation_size_) / 2; | 5482 (static_cast<uint64_t>(old_gen_size) + max_old_generation_size_) / 2; |
| 5454 return static_cast<size_t>(Min(limit, halfway_to_the_max)); | 5483 return static_cast<size_t>(Min(limit, halfway_to_the_max)); |
| 5455 } | 5484 } |
| 5456 | 5485 |
| 5457 size_t Heap::MinimumAllocationLimitGrowingStep() { | 5486 size_t Heap::MinimumAllocationLimitGrowingStep() { |
| 5458 const size_t kRegularAllocationLimitGrowingStep = 8; | 5487 const size_t kRegularAllocationLimitGrowingStep = 8; |
| 5459 const size_t kLowMemoryAllocationLimitGrowingStep = 2; | 5488 const size_t kLowMemoryAllocationLimitGrowingStep = 2; |
| 5460 size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB); | 5489 size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB); |
| 5461 return limit * (ShouldOptimizeForMemoryUsage() | 5490 return limit * (ShouldOptimizeForMemoryUsage() |
| 5462 ? kLowMemoryAllocationLimitGrowingStep | 5491 ? kLowMemoryAllocationLimitGrowingStep |
| 5463 : kRegularAllocationLimitGrowingStep); | 5492 : kRegularAllocationLimitGrowingStep); |
| 5464 } | 5493 } |
| 5465 | 5494 |
| 5466 void Heap::SetOldGenerationAllocationLimit(size_t old_gen_size, double gc_speed, | 5495 void Heap::SetOldGenerationAllocationLimit(size_t old_gen_size, double gc_speed, |
| 5467 double mutator_speed) { | 5496 double mutator_speed) { |
| 5468 double factor = HeapGrowingFactor(gc_speed, mutator_speed); | 5497 double max_factor = MaxHeapGrowingFactor(max_old_generation_size_); |
| 5498 double factor = HeapGrowingFactor(gc_speed, mutator_speed, max_factor); |
| 5469 | 5499 |
| 5470 if (FLAG_trace_gc_verbose) { | 5500 if (FLAG_trace_gc_verbose) { |
| 5471 isolate_->PrintWithTimestamp( | 5501 isolate_->PrintWithTimestamp( |
| 5472 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " | 5502 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " |
| 5473 "(gc=%.f, mutator=%.f)\n", | 5503 "(gc=%.f, mutator=%.f)\n", |
| 5474 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, gc_speed, | 5504 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, gc_speed, |
| 5475 mutator_speed); | 5505 mutator_speed); |
| 5476 } | 5506 } |
| 5477 | 5507 |
| 5478 if (IsMemoryConstrainedDevice()) { | |
| 5479 factor = Min(factor, kMaxHeapGrowingFactorMemoryConstrained); | |
| 5480 } | |
| 5481 | |
| 5482 if (memory_reducer_->ShouldGrowHeapSlowly() || | 5508 if (memory_reducer_->ShouldGrowHeapSlowly() || |
| 5483 ShouldOptimizeForMemoryUsage()) { | 5509 ShouldOptimizeForMemoryUsage()) { |
| 5484 factor = Min(factor, kConservativeHeapGrowingFactor); | 5510 factor = Min(factor, kConservativeHeapGrowingFactor); |
| 5485 } | 5511 } |
| 5486 | 5512 |
| 5487 if (FLAG_stress_compaction || ShouldReduceMemory()) { | 5513 if (FLAG_stress_compaction || ShouldReduceMemory()) { |
| 5488 factor = kMinHeapGrowingFactor; | 5514 factor = kMinHeapGrowingFactor; |
| 5489 } | 5515 } |
| 5490 | 5516 |
| 5491 if (FLAG_heap_growing_percent > 0) { | 5517 if (FLAG_heap_growing_percent > 0) { |
| 5492 factor = 1.0 + FLAG_heap_growing_percent / 100.0; | 5518 factor = 1.0 + FLAG_heap_growing_percent / 100.0; |
| 5493 } | 5519 } |
| 5494 | 5520 |
| 5495 old_generation_allocation_limit_ = | 5521 old_generation_allocation_limit_ = |
| 5496 CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5522 CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
| 5497 | 5523 |
| 5498 if (FLAG_trace_gc_verbose) { | 5524 if (FLAG_trace_gc_verbose) { |
| 5499 isolate_->PrintWithTimestamp( | 5525 isolate_->PrintWithTimestamp( |
| 5500 "Grow: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n", | 5526 "Grow: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n", |
| 5501 old_gen_size / KB, old_generation_allocation_limit_ / KB, factor); | 5527 old_gen_size / KB, old_generation_allocation_limit_ / KB, factor); |
| 5502 } | 5528 } |
| 5503 } | 5529 } |
| 5504 | 5530 |
| 5505 void Heap::DampenOldGenerationAllocationLimit(size_t old_gen_size, | 5531 void Heap::DampenOldGenerationAllocationLimit(size_t old_gen_size, |
| 5506 double gc_speed, | 5532 double gc_speed, |
| 5507 double mutator_speed) { | 5533 double mutator_speed) { |
| 5508 double factor = HeapGrowingFactor(gc_speed, mutator_speed); | 5534 double max_factor = MaxHeapGrowingFactor(max_old_generation_size_); |
| 5535 double factor = HeapGrowingFactor(gc_speed, mutator_speed, max_factor); |
| 5509 size_t limit = CalculateOldGenerationAllocationLimit(factor, old_gen_size); | 5536 size_t limit = CalculateOldGenerationAllocationLimit(factor, old_gen_size); |
| 5510 if (limit < old_generation_allocation_limit_) { | 5537 if (limit < old_generation_allocation_limit_) { |
| 5511 if (FLAG_trace_gc_verbose) { | 5538 if (FLAG_trace_gc_verbose) { |
| 5512 isolate_->PrintWithTimestamp( | 5539 isolate_->PrintWithTimestamp( |
| 5513 "Dampen: old size: %" PRIuS " KB, old limit: %" PRIuS | 5540 "Dampen: old size: %" PRIuS " KB, old limit: %" PRIuS |
| 5514 " KB, " | 5541 " KB, " |
| 5515 "new limit: %" PRIuS " KB (%.1f)\n", | 5542 "new limit: %" PRIuS " KB (%.1f)\n", |
| 5516 old_gen_size / KB, old_generation_allocation_limit_ / KB, limit / KB, | 5543 old_gen_size / KB, old_generation_allocation_limit_ / KB, limit / KB, |
| 5517 factor); | 5544 factor); |
| 5518 } | 5545 } |
| (...skipping 1081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6600 case LO_SPACE: | 6627 case LO_SPACE: |
| 6601 return "LO_SPACE"; | 6628 return "LO_SPACE"; |
| 6602 default: | 6629 default: |
| 6603 UNREACHABLE(); | 6630 UNREACHABLE(); |
| 6604 } | 6631 } |
| 6605 return NULL; | 6632 return NULL; |
| 6606 } | 6633 } |
| 6607 | 6634 |
| 6608 } // namespace internal | 6635 } // namespace internal |
| 6609 } // namespace v8 | 6636 } // namespace v8 |
| OLD | NEW |