Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: content/browser/memory/memory_coordinator_default_policy.cc

Issue 2867353002: memory coordinator: Introduce MemoryCoordinatorImpl::Policy (Closed)
Patch Set: Tweak Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/memory/memory_coordinator_default_policy.cc
diff --git a/content/browser/memory/memory_coordinator_default_policy.cc b/content/browser/memory/memory_coordinator_default_policy.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3632d4d34abd00353337f61ddfb267ce499a6405
--- /dev/null
+++ b/content/browser/memory/memory_coordinator_default_policy.cc
@@ -0,0 +1,121 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/memory/memory_coordinator_default_policy.h"
+
+namespace content {
+
+namespace {
+
+const int kDefaultBackgroundChildPurgeCandidatePeriodSeconds = 30;
+
+MemoryState CalculateMemoryStateForProcess(MemoryCondition condition,
+ bool is_visible) {
+ // The current heuristics for state calculation:
+ // - Foregrounded(visible) processes: THROTTLED when condition is CRITICAL,
+ // otherwise NORMAL.
+ // - Backgrounded(invisible) processes: THROTTLED when condition is
+ // WARNING/CRITICAL, otherwise NORMAL.
+ switch (condition) {
+ case MemoryCondition::NORMAL:
+ return MemoryState::NORMAL;
+ case MemoryCondition::WARNING:
+ return is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED;
+ case MemoryCondition::CRITICAL:
+ return MemoryState::THROTTLED;
+ }
+ NOTREACHED();
+ return MemoryState::NORMAL;
+}
+
+} // namespace
+
+MemoryCoordinatorDefaultPolicy::MemoryCoordinatorDefaultPolicy(
+ MemoryCoordinatorImpl* coordinator)
+ : coordinator_(coordinator) {
+ DCHECK(coordinator_);
+}
+
+MemoryCoordinatorDefaultPolicy::~MemoryCoordinatorDefaultPolicy() {}
+
+void MemoryCoordinatorDefaultPolicy::OnWarningCondition() {
+ TryToPurgeMemoryFromChildren(PurgeTarget::BACKGROUNDED);
+}
+
+void MemoryCoordinatorDefaultPolicy::OnCriticalCondition() {
+ coordinator_->DiscardTab();
+
+ // Prefer to purge memory from child processes than browser process because
+ // we prioritize the brower process.
+ if (TryToPurgeMemoryFromChildren(PurgeTarget::ALL))
+ return;
+
+ coordinator_->TryToPurgeMemoryFromBrowser();
+}
+
+void MemoryCoordinatorDefaultPolicy::OnConditionChanged(MemoryCondition prev,
+ MemoryCondition next) {
+ DCHECK(prev != next);
+ if (next == MemoryCondition::NORMAL) {
+ // Set NORMAL state to all clients/processes.
+ coordinator_->SetBrowserMemoryState(MemoryState::NORMAL);
+ SetMemoryStateToAllChildren(MemoryState::NORMAL);
+ } else if (next == MemoryCondition::WARNING) {
+ // Set NORMAL state to foreground proceses and clients in the browser
+ // process. Set THROTTLED state to background processes.
+ coordinator_->SetBrowserMemoryState(MemoryState::NORMAL);
+ for (auto& iter : coordinator_->children()) {
+ auto state =
+ iter.second.is_visible ? MemoryState::NORMAL : MemoryState::THROTTLED;
+ coordinator_->SetChildMemoryState(iter.first, state);
+ }
+ } else if (next == MemoryCondition::CRITICAL) {
+ // Set THROTTLED state to all clients/processes.
+ coordinator_->SetBrowserMemoryState(MemoryState::THROTTLED);
+ SetMemoryStateToAllChildren(MemoryState::THROTTLED);
+ }
+}
+
+void MemoryCoordinatorDefaultPolicy::OnChildVisibilityChanged(
+ int render_process_id,
+ bool is_visible) {
+ auto iter = coordinator_->children().find(render_process_id);
+ if (iter == coordinator_->children().end())
+ return;
+
+ iter->second.is_visible = is_visible;
+ if (!is_visible) {
+ // A backgrounded process becomes a candidate for purging memory when
+ // the process remains backgrounded for a certian period of time.
+ iter->second.can_purge_after =
+ coordinator_->NowTicks() +
+ base::TimeDelta::FromSeconds(
+ kDefaultBackgroundChildPurgeCandidatePeriodSeconds);
+ }
+ MemoryState new_state = CalculateMemoryStateForProcess(
+ coordinator_->GetMemoryCondition(), is_visible);
+ coordinator_->SetChildMemoryState(render_process_id, new_state);
+}
+
+void MemoryCoordinatorDefaultPolicy::SetMemoryStateToAllChildren(
+ MemoryState state) {
+ // It's OK to call SetChildMemoryState() unconditionally because it checks
+ // whether this state transition is valid.
+ for (auto& iter : coordinator_->children())
+ coordinator_->SetChildMemoryState(iter.first, state);
+}
+
+bool MemoryCoordinatorDefaultPolicy::TryToPurgeMemoryFromChildren(
+ PurgeTarget target) {
+ // TODO(bashi): Better to sort child processes based on their priorities.
+ for (auto& iter : coordinator_->children()) {
+ if (iter.second.is_visible && target == PurgeTarget::BACKGROUNDED)
+ continue;
+ if (coordinator_->TryToPurgeMemoryFromChild(iter.first))
+ return true;
+ }
+ return false;
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698