| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/memory/oom_priority_manager.h" | 5 #include "chrome/browser/memory/oom_priority_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "base/threading/thread.h" | 25 #include "base/threading/thread.h" |
| 26 #include "build/build_config.h" | 26 #include "build/build_config.h" |
| 27 #include "chrome/browser/browser_process.h" | 27 #include "chrome/browser/browser_process.h" |
| 28 #include "chrome/browser/memory/oom_memory_details.h" | 28 #include "chrome/browser/memory/oom_memory_details.h" |
| 29 #include "chrome/browser/memory/system_memory_stats_recorder.h" | 29 #include "chrome/browser/memory/system_memory_stats_recorder.h" |
| 30 #include "chrome/browser/ui/browser.h" | 30 #include "chrome/browser/ui/browser.h" |
| 31 #include "chrome/browser/ui/browser_iterator.h" | 31 #include "chrome/browser/ui/browser_iterator.h" |
| 32 #include "chrome/browser/ui/browser_list.h" | 32 #include "chrome/browser/ui/browser_list.h" |
| 33 #include "chrome/browser/ui/host_desktop.h" | 33 #include "chrome/browser/ui/host_desktop.h" |
| 34 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | 34 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
| 35 #include "chrome/browser/ui/tabs/tab_discard_state.h" |
| 35 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 36 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 36 #include "chrome/browser/ui/tabs/tab_utils.h" | 37 #include "chrome/browser/ui/tabs/tab_utils.h" |
| 37 #include "chrome/common/chrome_constants.h" | 38 #include "chrome/common/chrome_constants.h" |
| 38 #include "chrome/common/url_constants.h" | 39 #include "chrome/common/url_constants.h" |
| 39 #include "content/public/browser/browser_thread.h" | 40 #include "content/public/browser/browser_thread.h" |
| 40 #include "content/public/browser/render_process_host.h" | 41 #include "content/public/browser/render_process_host.h" |
| 41 #include "content/public/browser/web_contents.h" | 42 #include "content/public/browser/web_contents.h" |
| 42 | 43 |
| 43 #if defined(OS_CHROMEOS) | 44 #if defined(OS_CHROMEOS) |
| 44 #include "chrome/browser/memory/oom_priority_manager_delegate_chromeos.h" | 45 #include "chrome/browser/memory/oom_priority_manager_delegate_chromeos.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 89 |
| 89 return -1; | 90 return -1; |
| 90 } | 91 } |
| 91 | 92 |
| 92 } // namespace | 93 } // namespace |
| 93 | 94 |
| 94 //////////////////////////////////////////////////////////////////////////////// | 95 //////////////////////////////////////////////////////////////////////////////// |
| 95 // OomPriorityManager | 96 // OomPriorityManager |
| 96 | 97 |
| 97 OomPriorityManager::OomPriorityManager() | 98 OomPriorityManager::OomPriorityManager() |
| 98 : discard_count_(0), recent_tab_discard_(false) { | 99 : discard_count_(0), recent_tab_discard_(false), discard_once_(false) { |
| 99 #if defined(OS_CHROMEOS) | 100 #if defined(OS_CHROMEOS) |
| 100 delegate_.reset(new OomPriorityManagerDelegate); | 101 delegate_.reset(new OomPriorityManagerDelegate); |
| 101 #endif | 102 #endif |
| 102 } | 103 } |
| 103 | 104 |
| 104 OomPriorityManager::~OomPriorityManager() { | 105 OomPriorityManager::~OomPriorityManager() { |
| 105 Stop(); | 106 Stop(); |
| 106 } | 107 } |
| 107 | 108 |
| 108 void OomPriorityManager::Start() { | 109 void OomPriorityManager::Start(bool discard_once) { |
| 110 discard_once_ = discard_once; |
| 109 if (!update_timer_.IsRunning()) { | 111 if (!update_timer_.IsRunning()) { |
| 110 update_timer_.Start(FROM_HERE, | 112 update_timer_.Start(FROM_HERE, |
| 111 TimeDelta::FromSeconds(kAdjustmentIntervalSeconds), | 113 TimeDelta::FromSeconds(kAdjustmentIntervalSeconds), |
| 112 this, &OomPriorityManager::UpdateTimerCallback); | 114 this, &OomPriorityManager::UpdateTimerCallback); |
| 113 } | 115 } |
| 114 if (!recent_tab_discard_timer_.IsRunning()) { | 116 if (!recent_tab_discard_timer_.IsRunning()) { |
| 115 recent_tab_discard_timer_.Start( | 117 recent_tab_discard_timer_.Start( |
| 116 FROM_HERE, TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds), | 118 FROM_HERE, TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds), |
| 117 this, &OomPriorityManager::RecordRecentTabDiscard); | 119 this, &OomPriorityManager::RecordRecentTabDiscard); |
| 118 } | 120 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 // discard the entire set together, or use that in the priority computation. | 173 // discard the entire set together, or use that in the priority computation. |
| 172 bool OomPriorityManager::DiscardTab() { | 174 bool OomPriorityManager::DiscardTab() { |
| 173 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 175 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 174 TabStatsList stats = GetTabStats(); | 176 TabStatsList stats = GetTabStats(); |
| 175 if (stats.empty()) | 177 if (stats.empty()) |
| 176 return false; | 178 return false; |
| 177 // Loop until we find a non-discarded tab to kill. | 179 // Loop until we find a non-discarded tab to kill. |
| 178 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin(); | 180 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin(); |
| 179 stats_rit != stats.rend(); ++stats_rit) { | 181 stats_rit != stats.rend(); ++stats_rit) { |
| 180 int64 least_important_tab_id = stats_rit->tab_contents_id; | 182 int64 least_important_tab_id = stats_rit->tab_contents_id; |
| 181 if (DiscardTabById(least_important_tab_id)) | 183 if (CanDiscardTab(least_important_tab_id) && |
| 184 DiscardTabById(least_important_tab_id)) |
| 182 return true; | 185 return true; |
| 183 } | 186 } |
| 184 return false; | 187 return false; |
| 185 } | 188 } |
| 186 | 189 |
| 187 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { | 190 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { |
| 188 TabStripModel* model; | 191 TabStripModel* model; |
| 189 int idx = FindTabStripModelById(target_web_contents_id, &model); | 192 int idx = FindTabStripModelById(target_web_contents_id, &model); |
| 190 | 193 |
| 191 if (idx == -1) | 194 if (idx == -1) |
| 192 return false; | 195 return false; |
| 193 | 196 |
| 194 // Can't discard tabs that are already discarded or active. | 197 // Can't discard active tabs |
| 195 if (model->IsTabDiscarded(idx) || (model->active_index() == idx)) | 198 if (model->active_index() == idx) |
| 196 return false; | 199 return false; |
| 197 | 200 |
| 198 // We also ignore tabs that are playing audio as it's too distruptive to | 201 WebContents* web_contents = model->GetWebContentsAt(idx); |
| 199 // the user experience. | 202 // Can't discard tabs that are already discarded. |
| 200 if (model->GetWebContentsAt(idx)->WasRecentlyAudible()) | 203 if (TabDiscardState::IsDiscarded(web_contents)) |
| 201 return false; | 204 return false; |
| 202 | 205 |
| 203 VLOG(1) << "Discarding tab " << idx << " id " << target_web_contents_id; | 206 VLOG(1) << "Discarding tab " << idx << " id " << target_web_contents_id; |
| 204 // Record statistics before discarding because we want to capture the | 207 // Record statistics before discarding because we want to capture the |
| 205 // memory state that lead to the discard. | 208 // memory state that lead to the discard. |
| 206 RecordDiscardStatistics(); | 209 RecordDiscardStatistics(); |
| 207 model->DiscardWebContentsAt(idx); | 210 model->DiscardWebContentsAt(idx); |
| 208 recent_tab_discard_ = true; | 211 recent_tab_discard_ = true; |
| 209 | 212 |
| 210 return true; | 213 return true; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 for (int i = 0; i < model->count(); i++) { | 421 for (int i = 0; i < model->count(); i++) { |
| 419 WebContents* contents = model->GetWebContentsAt(i); | 422 WebContents* contents = model->GetWebContentsAt(i); |
| 420 if (!contents->IsCrashed()) { | 423 if (!contents->IsCrashed()) { |
| 421 TabStats stats; | 424 TabStats stats; |
| 422 stats.is_app = is_browser_for_app; | 425 stats.is_app = is_browser_for_app; |
| 423 stats.is_internal_page = | 426 stats.is_internal_page = |
| 424 IsInternalPage(contents->GetLastCommittedURL()); | 427 IsInternalPage(contents->GetLastCommittedURL()); |
| 425 stats.is_playing_audio = contents->WasRecentlyAudible(); | 428 stats.is_playing_audio = contents->WasRecentlyAudible(); |
| 426 stats.is_pinned = model->IsTabPinned(i); | 429 stats.is_pinned = model->IsTabPinned(i); |
| 427 stats.is_selected = browser_active && model->IsTabSelected(i); | 430 stats.is_selected = browser_active && model->IsTabSelected(i); |
| 428 stats.is_discarded = model->IsTabDiscarded(i); | 431 stats.is_discarded = TabDiscardState::IsDiscarded(contents); |
| 432 stats.discard_count = TabDiscardState::DiscardCount(contents); |
| 429 stats.last_active = contents->GetLastActiveTime(); | 433 stats.last_active = contents->GetLastActiveTime(); |
| 430 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 434 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
| 431 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); | 435 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); |
| 432 #if defined(OS_CHROMEOS) | 436 #if defined(OS_CHROMEOS) |
| 433 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id); | 437 stats.oom_score = delegate_->GetOomScore(stats.child_process_host_id); |
| 434 #endif | 438 #endif |
| 435 stats.title = contents->GetTitle(); | 439 stats.title = contents->GetTitle(); |
| 436 stats.tab_contents_id = IdFromWebContents(contents); | 440 stats.tab_contents_id = IdFromWebContents(contents); |
| 437 stats_list->push_back(stats); | 441 stats_list->push_back(stats); |
| 438 } | 442 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 450 | 454 |
| 451 // For the moment we only do something when we reach a critical state. | 455 // For the moment we only do something when we reach a critical state. |
| 452 if (memory_pressure_level == | 456 if (memory_pressure_level == |
| 453 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { | 457 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
| 454 LogMemoryAndDiscardTab(); | 458 LogMemoryAndDiscardTab(); |
| 455 } | 459 } |
| 456 // TODO(skuhne): If more memory pressure levels are introduced, we might | 460 // TODO(skuhne): If more memory pressure levels are introduced, we might |
| 457 // consider to call PurgeBrowserMemory() before CRITICAL is reached. | 461 // consider to call PurgeBrowserMemory() before CRITICAL is reached. |
| 458 } | 462 } |
| 459 | 463 |
| 464 bool OomPriorityManager::CanDiscardTab(int64 target_web_contents_id) const { |
| 465 TabStripModel* model; |
| 466 int idx = FindTabStripModelById(target_web_contents_id, &model); |
| 467 |
| 468 if (idx == -1) |
| 469 return false; |
| 470 |
| 471 WebContents* web_contents = model->GetWebContentsAt(idx); |
| 472 // We do not discard tabs that are playing audio as it's too distruptive to |
| 473 // the user experience. |
| 474 if (web_contents->WasRecentlyAudible()) |
| 475 return false; |
| 476 |
| 477 // We also make sure not to discard a previously discarded tab if that's the |
| 478 // desired behavior. |
| 479 if (discard_once_ && TabDiscardState::DiscardCount(web_contents) > 0) |
| 480 return false; |
| 481 |
| 482 return true; |
| 483 } |
| 484 |
| 460 } // namespace memory | 485 } // namespace memory |
| OLD | NEW |