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 |