| // Copyright 2016 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_condition_observer.h" |
| |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "content/browser/memory/memory_monitor.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // An expected renderer size. These values come from the median of appropriate |
| // UMA stats. |
| #if defined(OS_ANDROID) || defined(OS_IOS) |
| const int kExpectedRendererSizeMB = 40; |
| #elif defined(OS_WIN) |
| const int kExpectedRendererSizeMB = 70; |
| #else // Mac, Linux, and ChromeOS |
| const int kExpectedRendererSizeMB = 120; |
| #endif |
| |
| const int kNewRenderersUntilCritical = 2; |
| const int kDefaultMonitoringIntervalSeconds = 1; |
| const int kMonitoringIntervalBackgroundedSeconds = 120; |
| |
| } // namespace |
| |
| MemoryConditionObserver::MemoryConditionObserver( |
| MemoryCoordinatorImpl* coordinator, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
| : coordinator_(coordinator), task_runner_(task_runner) { |
| DCHECK(coordinator_); |
| monitoring_interval_ = |
| base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); |
| monitoring_interval_foregrounded_ = |
| base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); |
| monitoring_interval_backgrounded_ = |
| base::TimeDelta::FromSeconds(kMonitoringIntervalBackgroundedSeconds); |
| } |
| |
| MemoryConditionObserver::~MemoryConditionObserver() {} |
| |
| void MemoryConditionObserver::ScheduleUpdateCondition(base::TimeDelta delay) { |
| update_condition_closure_.Reset(base::Bind( |
| &MemoryConditionObserver::UpdateCondition, base::Unretained(this))); |
| task_runner_->PostDelayedTask(FROM_HERE, update_condition_closure_.callback(), |
| delay); |
| } |
| |
| void MemoryConditionObserver::OnForegrounded() { |
| SetMonitoringInterval(monitoring_interval_foregrounded_); |
| } |
| |
| void MemoryConditionObserver::OnBackgrounded() { |
| SetMonitoringInterval(monitoring_interval_backgrounded_); |
| } |
| |
| void MemoryConditionObserver::SetMonitoringInterval(base::TimeDelta interval) { |
| DCHECK(!interval.is_zero()); |
| if (interval == monitoring_interval_) |
| return; |
| monitoring_interval_ = interval; |
| ScheduleUpdateCondition(interval); |
| } |
| |
| MemoryCondition MemoryConditionObserver::CalculateNextCondition() { |
| int available = |
| coordinator_->memory_monitor()->GetFreeMemoryUntilCriticalMB(); |
| |
| // TODO(chrisha): Move this histogram recording to a better place when |
| // https://codereview.chromium.org/2479673002/ is landed. |
| UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Coordinator.FreeMemoryUntilCritical", |
| available); |
| |
| int expected_renderer_count = available / kExpectedRendererSizeMB; |
| if (available <= 0 || expected_renderer_count < kNewRenderersUntilCritical) |
| return MemoryCondition::CRITICAL; |
| return MemoryCondition::NORMAL; |
| } |
| |
| void MemoryConditionObserver::UpdateCondition() { |
| auto next_condition = CalculateNextCondition(); |
| coordinator_->UpdateConditionIfNeeded(next_condition); |
| ScheduleUpdateCondition(monitoring_interval_); |
| } |
| |
| |
| } // namespace content |