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

Unified Diff: chrome/browser/memory/tab_manager.cc

Issue 2711093002: Purge once random minutes(between 30min and 60min) after backgrounded. (Closed)
Patch Set: Fixed Created 3 years, 9 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
« no previous file with comments | « chrome/browser/memory/tab_manager.h ('k') | chrome/browser/memory/tab_manager_browsertest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/memory/tab_manager.cc
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc
index 74baafa6bcff792bb5db4b5c517a9b35a2765bc8..0cccbee9985264351bcb30aad2ee17f8b6d826cf 100644
--- a/chrome/browser/memory/tab_manager.cc
+++ b/chrome/browser/memory/tab_manager.cc
@@ -20,6 +20,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/observer_list.h"
#include "base/process/process.h"
+#include "base/rand_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -80,35 +81,17 @@ const int kAdjustmentIntervalSeconds = 10;
const int kRecentTabDiscardIntervalSeconds = 60;
#endif
-// If there has been no priority adjustment in this interval, assume the
-// machine was suspended and correct the timing statistics.
-const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4;
-
-// A suspended renderer is suspended for this duration.
-constexpr base::TimeDelta kDurationOfRendererSuspension =
- base::TimeDelta::FromSeconds(1200);
-
-// A resumed renderer is resumed for this duration.
-constexpr base::TimeDelta kDurationOfRendererResumption =
- base::TimeDelta::FromSeconds(10);
-
// The time during which a tab is protected from discarding after it stops being
// audible.
const int kAudioProtectionTimeSeconds = 60;
-int FindTabStripModelById(int64_t target_web_contents_id,
- TabStripModel** model) {
- DCHECK(model);
- for (auto* browser : *BrowserList::GetInstance()) {
- TabStripModel* local_model = browser->tab_strip_model();
- for (int idx = 0; idx < local_model->count(); idx++) {
- WebContents* web_contents = local_model->GetWebContentsAt(idx);
- int64_t web_contents_id = TabManager::IdFromWebContents(web_contents);
- if (web_contents_id == target_web_contents_id) {
- *model = local_model;
- return idx;
- }
- }
+int FindWebContentsById(const TabStripModel* model,
+ int64_t target_web_contents_id) {
+ for (int idx = 0; idx < model->count(); idx++) {
+ WebContents* web_contents = model->GetWebContentsAt(idx);
+ int64_t web_contents_id = TabManager::IdFromWebContents(web_contents);
+ if (web_contents_id == target_web_contents_id)
+ return idx;
}
return -1;
@@ -139,7 +122,7 @@ void NotifyRendererProcess(
////////////////////////////////////////////////////////////////////////////////
// TabManager
-constexpr base::TimeDelta TabManager::kDefaultTimeToFirstPurge;
+constexpr base::TimeDelta TabManager::kDefaultMinTimeToPurge;
TabManager::TabManager()
: discard_count_(0),
@@ -227,13 +210,12 @@ void TabManager::Start() {
// https://docs.google.com/document/d/1hPHkKtXXBTlsZx9s-9U17XC-ofEIzPo9FYbBEc7PPbk/edit?usp=sharing
std::string purge_and_suspend_time = variations::GetVariationParamValue(
"PurgeAndSuspend", "purge-and-suspend-time");
- unsigned int time_to_first_purge_sec = 0;
+ unsigned int min_time_to_purge_sec = 0;
if (purge_and_suspend_time.empty() ||
- !base::StringToUint(purge_and_suspend_time, &time_to_first_purge_sec))
- time_to_first_suspension_ = kDefaultTimeToFirstPurge;
+ !base::StringToUint(purge_and_suspend_time, &min_time_to_purge_sec))
+ min_time_to_purge_ = kDefaultMinTimeToPurge;
else
- time_to_first_suspension_ =
- base::TimeDelta::FromSeconds(time_to_first_purge_sec);
+ min_time_to_purge_ = base::TimeDelta::FromSeconds(min_time_to_purge_sec);
}
void TabManager::Stop() {
@@ -242,6 +224,36 @@ void TabManager::Stop() {
memory_pressure_listener_.reset();
}
+int TabManager::FindTabStripModelById(int64_t target_web_contents_id,
+ TabStripModel** model) const {
+ DCHECK(model);
+ // TODO(tasak): Move this code to a TabStripModel enumeration delegate!
+ if (!test_tab_strip_models_.empty()) {
+ for (size_t i = 0; i < test_tab_strip_models_.size(); ++i) {
+ TabStripModel* local_model =
+ const_cast<TabStripModel*>(test_tab_strip_models_[i].first);
+ int idx = FindWebContentsById(local_model, target_web_contents_id);
+ if (idx != -1) {
+ *model = local_model;
+ return idx;
+ }
+ }
+
+ return -1;
+ }
+
+ for (auto* browser : *BrowserList::GetInstance()) {
+ TabStripModel* local_model = browser->tab_strip_model();
+ int idx = FindWebContentsById(local_model, target_web_contents_id);
+ if (idx != -1) {
+ *model = local_model;
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
TabStatsList TabManager::GetTabStats() const {
TabStatsList stats_list(GetUnsortedTabStats());
@@ -452,7 +464,7 @@ content::WebContents* TabManager::GetWebContentsById(
}
bool TabManager::CanSuspendBackgroundedRenderer(int render_process_id) const {
- // A renderer can be suspended if it's not playing media.
+ // A renderer can be purged if it's not playing media.
auto tab_stats = GetUnsortedTabStats();
for (auto& tab : tab_stats) {
if (tab.child_process_host_id != render_process_id)
@@ -685,8 +697,7 @@ void TabManager::AddTabStats(const TabStripModel* model,
// This function is called when |update_timer_| fires. It will adjust the clock
// if needed (if it detects that the machine was asleep) and will fire the stats
// updating on ChromeOS via the delegate. This function also tries to purge
-// cache memory and suspend tabs which becomes and keeps backgrounded for a
-// while.
+// cache memory.
void TabManager::UpdateTimerCallback() {
// If Chrome is shutting down, do not do anything.
if (g_browser_process->IsShuttingDown())
@@ -695,17 +706,6 @@ void TabManager::UpdateTimerCallback() {
if (BrowserList::GetInstance()->empty())
return;
- // Check for a discontinuity in time caused by the machine being suspended.
- if (!last_adjust_time_.is_null()) {
- TimeDelta suspend_time = NowTicks() - last_adjust_time_;
- if (suspend_time.InSeconds() > kSuspendThresholdSeconds) {
- // System was probably suspended, move the event timers forward in time so
- // when they get subtracted out later, "uptime" is being counted.
- start_time_ += suspend_time;
- if (!last_discard_time_.is_null())
- last_discard_time_ += suspend_time;
- }
- }
last_adjust_time_ = NowTicks();
#if defined(OS_CHROMEOS)
@@ -714,38 +714,26 @@ void TabManager::UpdateTimerCallback() {
delegate_->AdjustOomPriorities(stats_list);
#endif
- PurgeAndSuspendBackgroundedTabs();
+ PurgeBackgroundedTabsIfNeeded();
}
-TabManager::PurgeAndSuspendState TabManager::GetNextPurgeAndSuspendState(
- content::WebContents* content,
- base::TimeTicks current_time,
- const base::TimeDelta& time_to_first_suspension) const {
- DCHECK(content);
- PurgeAndSuspendState state =
- GetWebContentsData(content)->GetPurgeAndSuspendState();
-
- auto time_passed = current_time -
- GetWebContentsData(content)->LastPurgeAndSuspendModifiedTime();
- switch (state) {
- case RUNNING:
- if (time_passed > time_to_first_suspension)
- return SUSPENDED;
- break;
- case RESUMED:
- if (time_passed > kDurationOfRendererResumption)
- return SUSPENDED;
- break;
- case SUSPENDED:
- if (time_passed > kDurationOfRendererSuspension)
- return RESUMED;
- break;
- }
- return state;
+base::TimeDelta TabManager::GetTimeToPurge(
+ base::TimeDelta min_time_to_purge) const {
+ return base::TimeDelta::FromSeconds(
+ base::RandInt(min_time_to_purge.InSeconds(),
+ min_time_to_purge.InSeconds() * kMinMaxTimeToPurgeRatio));
+}
+
+bool TabManager::ShouldPurgeNow(content::WebContents* content) const {
+ if (GetWebContentsData(content)->is_purged())
+ return false;
+
+ base::TimeDelta time_passed =
+ NowTicks() - GetWebContentsData(content)->LastInactiveTime();
+ return time_passed > GetWebContentsData(content)->time_to_purge();
}
-void TabManager::PurgeAndSuspendBackgroundedTabs() {
- base::TimeTicks current_time = NowTicks();
+void TabManager::PurgeBackgroundedTabsIfNeeded() {
auto tab_stats = GetUnsortedTabStats();
for (auto& tab : tab_stats) {
if (!tab.render_process_host->IsProcessBackgrounded())
@@ -757,34 +745,16 @@ void TabManager::PurgeAndSuspendBackgroundedTabs() {
if (!content)
continue;
- PurgeAndSuspendState current_state =
- GetWebContentsData(content)->GetPurgeAndSuspendState();
- // If the tab's purge-and-suspend state is not RUNNING, the tab should be
- // backgrounded. Since tab.last_hidden is updated everytime the tab is
- // hidden, we should see tab.last_hidden < last_modified_time.
- DCHECK(current_state == RUNNING ||
- tab.last_hidden <
- GetWebContentsData(content)->LastPurgeAndSuspendModifiedTime());
- PurgeAndSuspendState next_state = GetNextPurgeAndSuspendState(
- content, current_time, time_to_first_suspension_);
- if (current_state == next_state)
+ bool purge_now = ShouldPurgeNow(content);
+ if (!purge_now)
continue;
- // TODO(hajimehoshi): Now calling PurgeAndSuspend is implemented without
- // timers for simplicity, so PurgeAndSuspend is called even after the
- // renderer is purged and suspended once. This should be replaced with
- // timers if we want necessary and sufficient signals.
- GetWebContentsData(content)->SetPurgeAndSuspendState(next_state);
- switch (next_state) {
- case SUSPENDED:
- tab.render_process_host->PurgeAndSuspend();
- break;
- case RESUMED:
- tab.render_process_host->Resume();
- break;
- case RUNNING:
- NOTREACHED();
- }
+ // Since |content|'s tab is kept inactive and background for more than
+ // time-to-purge time, its purged state changes: false => true.
+ GetWebContentsData(content)->set_is_purged(true);
+ // TODO(tasak): rename PurgeAndSuspend with a better name, e.g.
+ // RequestPurgeCache, because we don't suspend any renderers.
+ tab.render_process_host->PurgeAndSuspend();
}
}
@@ -824,6 +794,9 @@ WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
GetWebContentsData(null_contents)->SetDiscardState(true);
GetWebContentsData(null_contents)->IncrementDiscardCount();
+ // Make the tab PURGED to avoid purging null_contents.
+ GetWebContentsData(null_contents)->set_is_purged(true);
+
// Discard the old tab's renderer.
// TODO(jamescook): This breaks script connections with other tabs.
// Find a different approach that doesn't do that, perhaps based on navigation
@@ -885,11 +858,16 @@ void TabManager::ActiveTabChanged(content::WebContents* old_contents,
int index,
int reason) {
GetWebContentsData(new_contents)->SetDiscardState(false);
- GetWebContentsData(new_contents)->SetPurgeAndSuspendState(RUNNING);
+ // When ActiveTabChanged, |new_contents| purged state changes to be false.
+ GetWebContentsData(new_contents)->set_is_purged(false);
// If |old_contents| is set, that tab has switched from being active to
// inactive, so record the time of that transition.
- if (old_contents)
+ if (old_contents) {
GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks());
+ // Re-setting time-to-purge every time a tab becomes inactive.
+ GetWebContentsData(old_contents)
+ ->set_time_to_purge(GetTimeToPurge(min_time_to_purge_));
+ }
}
void TabManager::TabInsertedAt(TabStripModel* tab_strip_model,
@@ -904,6 +882,9 @@ void TabManager::TabInsertedAt(TabStripModel* tab_strip_model,
// A new background tab is similar to having a tab switch from being active to
// inactive.
GetWebContentsData(contents)->SetLastInactiveTime(NowTicks());
+ // Re-setting time-to-purge every time a tab becomes inactive.
+ GetWebContentsData(contents)->set_time_to_purge(
+ GetTimeToPurge(min_time_to_purge_));
}
bool TabManager::IsMediaTab(WebContents* contents) const {
« no previous file with comments | « chrome/browser/memory/tab_manager.h ('k') | chrome/browser/memory/tab_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698