| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium 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 "content/browser/memory/memory_coordinator_default_policy.h" | 5 #include "content/browser/memory/memory_coordinator_default_policy.h" |
| 6 | 6 |
| 7 namespace content { | 7 namespace content { |
| 8 | 8 |
| 9 namespace { | 9 namespace { |
| 10 | 10 |
| 11 const int kDefaultBackgroundChildPurgeCandidatePeriodSeconds = 30; | 11 const int kDefaultBackgroundChildPurgeCandidatePeriodSeconds = 30; |
| 12 | 12 |
| 13 MemoryState CalculateMemoryStateForProcess(MemoryCondition condition, | 13 MemoryState CalculateMemoryStateForProcess(MemoryCondition condition) { |
| 14 bool is_visible) { | 14 if (condition == MemoryCondition::CRITICAL) |
| 15 // The current heuristics for state calculation: | 15 return MemoryState::THROTTLED; |
| 16 // - Foregrounded(visible) processes: THROTTLED when condition is CRITICAL, | |
| 17 // otherwise NORMAL. | |
| 18 // - Backgrounded(invisible) processes: THROTTLED when condition is | |
| 19 // WARNING/CRITICAL, otherwise NORMAL. | |
| 20 switch (condition) { | |
| 21 case MemoryCondition::NORMAL: | |
| 22 return MemoryState::NORMAL; | |
| 23 case MemoryCondition::WARNING: | |
| 24 return is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED; | |
| 25 case MemoryCondition::CRITICAL: | |
| 26 return MemoryState::THROTTLED; | |
| 27 } | |
| 28 NOTREACHED(); | |
| 29 return MemoryState::NORMAL; | 16 return MemoryState::NORMAL; |
| 30 } | 17 } |
| 31 | 18 |
| 32 } // namespace | 19 } // namespace |
| 33 | 20 |
| 34 MemoryCoordinatorDefaultPolicy::MemoryCoordinatorDefaultPolicy( | 21 MemoryCoordinatorDefaultPolicy::MemoryCoordinatorDefaultPolicy( |
| 35 MemoryCoordinatorImpl* coordinator) | 22 MemoryCoordinatorImpl* coordinator) |
| 36 : coordinator_(coordinator) { | 23 : coordinator_(coordinator) { |
| 37 DCHECK(coordinator_); | 24 DCHECK(coordinator_); |
| 38 } | 25 } |
| 39 | 26 |
| 40 MemoryCoordinatorDefaultPolicy::~MemoryCoordinatorDefaultPolicy() {} | 27 MemoryCoordinatorDefaultPolicy::~MemoryCoordinatorDefaultPolicy() {} |
| 41 | 28 |
| 42 void MemoryCoordinatorDefaultPolicy::OnWarningCondition() { | |
| 43 TryToPurgeMemoryFromChildren(PurgeTarget::BACKGROUNDED); | |
| 44 } | |
| 45 | |
| 46 void MemoryCoordinatorDefaultPolicy::OnCriticalCondition() { | 29 void MemoryCoordinatorDefaultPolicy::OnCriticalCondition() { |
| 47 coordinator_->DiscardTab(); | 30 coordinator_->DiscardTab(); |
| 48 | 31 |
| 49 // Prefer to purge memory from child processes than browser process because | 32 // Prefer to purge memory from child processes than browser process because |
| 50 // we prioritize the brower process. | 33 // we prioritize the brower process. |
| 51 if (TryToPurgeMemoryFromChildren(PurgeTarget::ALL)) | 34 if (TryToPurgeMemoryFromChildren(PurgeTarget::ALL)) |
| 52 return; | 35 return; |
| 53 | 36 |
| 54 coordinator_->TryToPurgeMemoryFromBrowser(); | 37 coordinator_->TryToPurgeMemoryFromBrowser(); |
| 55 } | 38 } |
| 56 | 39 |
| 57 void MemoryCoordinatorDefaultPolicy::OnConditionChanged(MemoryCondition prev, | 40 void MemoryCoordinatorDefaultPolicy::OnConditionChanged(MemoryCondition prev, |
| 58 MemoryCondition next) { | 41 MemoryCondition next) { |
| 59 DCHECK(prev != next); | 42 DCHECK(prev != next); |
| 60 if (next == MemoryCondition::NORMAL) { | 43 if (next == MemoryCondition::NORMAL) { |
| 61 // Set NORMAL state to all clients/processes. | 44 // Set NORMAL state to all clients/processes. |
| 62 coordinator_->SetBrowserMemoryState(MemoryState::NORMAL); | 45 coordinator_->SetBrowserMemoryState(MemoryState::NORMAL); |
| 63 SetMemoryStateToAllChildren(MemoryState::NORMAL); | 46 SetMemoryStateToAllChildren(MemoryState::NORMAL); |
| 64 } else if (next == MemoryCondition::WARNING) { | |
| 65 // Set NORMAL state to foreground proceses and clients in the browser | |
| 66 // process. Set THROTTLED state to background processes. | |
| 67 coordinator_->SetBrowserMemoryState(MemoryState::NORMAL); | |
| 68 for (auto& iter : coordinator_->children()) { | |
| 69 auto state = | |
| 70 iter.second.is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED; | |
| 71 coordinator_->SetChildMemoryState(iter.first, state); | |
| 72 } | |
| 73 } else if (next == MemoryCondition::CRITICAL) { | 47 } else if (next == MemoryCondition::CRITICAL) { |
| 74 // Set THROTTLED state to all clients/processes. | 48 // Set THROTTLED state to all clients/processes. |
| 75 coordinator_->SetBrowserMemoryState(MemoryState::THROTTLED); | 49 coordinator_->SetBrowserMemoryState(MemoryState::THROTTLED); |
| 76 SetMemoryStateToAllChildren(MemoryState::THROTTLED); | 50 SetMemoryStateToAllChildren(MemoryState::THROTTLED); |
| 77 } | 51 } |
| 78 } | 52 } |
| 79 | 53 |
| 80 void MemoryCoordinatorDefaultPolicy::OnChildVisibilityChanged( | 54 void MemoryCoordinatorDefaultPolicy::OnChildVisibilityChanged( |
| 81 int render_process_id, | 55 int render_process_id, |
| 82 bool is_visible) { | 56 bool is_visible) { |
| 83 auto iter = coordinator_->children().find(render_process_id); | 57 auto iter = coordinator_->children().find(render_process_id); |
| 84 if (iter == coordinator_->children().end()) | 58 if (iter == coordinator_->children().end()) |
| 85 return; | 59 return; |
| 86 | 60 |
| 87 iter->second.is_visible = is_visible; | 61 iter->second.is_visible = is_visible; |
| 88 if (!is_visible) { | 62 if (!is_visible) { |
| 89 // A backgrounded process becomes a candidate for purging memory when | 63 // A backgrounded process becomes a candidate for purging memory when |
| 90 // the process remains backgrounded for a certian period of time. | 64 // the process remains backgrounded for a certian period of time. |
| 91 iter->second.can_purge_after = | 65 iter->second.can_purge_after = |
| 92 coordinator_->NowTicks() + | 66 coordinator_->NowTicks() + |
| 93 base::TimeDelta::FromSeconds( | 67 base::TimeDelta::FromSeconds( |
| 94 kDefaultBackgroundChildPurgeCandidatePeriodSeconds); | 68 kDefaultBackgroundChildPurgeCandidatePeriodSeconds); |
| 95 } | 69 } |
| 96 MemoryState new_state = CalculateMemoryStateForProcess( | 70 MemoryState new_state = |
| 97 coordinator_->GetMemoryCondition(), is_visible); | 71 CalculateMemoryStateForProcess(coordinator_->GetMemoryCondition()); |
| 98 coordinator_->SetChildMemoryState(render_process_id, new_state); | 72 coordinator_->SetChildMemoryState(render_process_id, new_state); |
| 99 } | 73 } |
| 100 | 74 |
| 101 void MemoryCoordinatorDefaultPolicy::SetMemoryStateToAllChildren( | 75 void MemoryCoordinatorDefaultPolicy::SetMemoryStateToAllChildren( |
| 102 MemoryState state) { | 76 MemoryState state) { |
| 103 // It's OK to call SetChildMemoryState() unconditionally because it checks | 77 // It's OK to call SetChildMemoryState() unconditionally because it checks |
| 104 // whether this state transition is valid. | 78 // whether this state transition is valid. |
| 105 for (auto& iter : coordinator_->children()) | 79 for (auto& iter : coordinator_->children()) |
| 106 coordinator_->SetChildMemoryState(iter.first, state); | 80 coordinator_->SetChildMemoryState(iter.first, state); |
| 107 } | 81 } |
| 108 | 82 |
| 109 bool MemoryCoordinatorDefaultPolicy::TryToPurgeMemoryFromChildren( | 83 bool MemoryCoordinatorDefaultPolicy::TryToPurgeMemoryFromChildren( |
| 110 PurgeTarget target) { | 84 PurgeTarget target) { |
| 111 // TODO(bashi): Better to sort child processes based on their priorities. | 85 // TODO(bashi): Better to sort child processes based on their priorities. |
| 112 for (auto& iter : coordinator_->children()) { | 86 for (auto& iter : coordinator_->children()) { |
| 113 if (iter.second.is_visible && target == PurgeTarget::BACKGROUNDED) | 87 if (iter.second.is_visible && target == PurgeTarget::BACKGROUNDED) |
| 114 continue; | 88 continue; |
| 115 if (coordinator_->TryToPurgeMemoryFromChild(iter.first)) | 89 if (coordinator_->TryToPurgeMemoryFromChild(iter.first)) |
| 116 return true; | 90 return true; |
| 117 } | 91 } |
| 118 return false; | 92 return false; |
| 119 } | 93 } |
| 120 | 94 |
| 121 } // namespace content | 95 } // namespace content |
| OLD | NEW |