Index: chrome/browser/chromeos/memory/oom_priority_manager.cc |
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc |
deleted file mode 100644 |
index 093cec3c358e7fc17becf391940ac6f983440117..0000000000000000000000000000000000000000 |
--- a/chrome/browser/chromeos/memory/oom_priority_manager.cc |
+++ /dev/null |
@@ -1,624 +0,0 @@ |
-// Copyright (c) 2012 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 "chrome/browser/chromeos/memory/oom_priority_manager.h" |
- |
-#include <algorithm> |
-#include <set> |
-#include <vector> |
- |
-#include "ash/multi_profile_uma.h" |
-#include "ash/session/session_state_delegate.h" |
-#include "ash/shell.h" |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/command_line.h" |
-#include "base/memory/memory_pressure_monitor.h" |
-#include "base/metrics/field_trial.h" |
-#include "base/metrics/histogram.h" |
-#include "base/process/process.h" |
-#include "base/strings/string16.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/synchronization/lock.h" |
-#include "base/threading/thread.h" |
-#include "build/build_config.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/browser_process_platform_part_chromeos.h" |
-#include "chrome/browser/chromeos/memory/low_memory_observer.h" |
-#include "chrome/browser/chromeos/memory/oom_memory_details.h" |
-#include "chrome/browser/chromeos/memory/system_memory_stats_recorder.h" |
-#include "chrome/browser/ui/browser.h" |
-#include "chrome/browser/ui/browser_iterator.h" |
-#include "chrome/browser/ui/browser_list.h" |
-#include "chrome/browser/ui/host_desktop.h" |
-#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
-#include "chrome/browser/ui/tabs/tab_strip_model.h" |
-#include "chrome/browser/ui/tabs/tab_utils.h" |
-#include "chrome/common/chrome_constants.h" |
-#include "chrome/common/url_constants.h" |
-#include "chromeos/chromeos_switches.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/notification_service.h" |
-#include "content/public/browser/notification_types.h" |
-#include "content/public/browser/render_process_host.h" |
-#include "content/public/browser/render_widget_host.h" |
-#include "content/public/browser/web_contents.h" |
-#include "content/public/browser/zygote_host_linux.h" |
- |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using content::BrowserThread; |
-using content::WebContents; |
- |
-namespace chromeos { |
- |
-namespace { |
- |
-// The default interval in seconds after which to adjust the oom_score_adj |
-// value. |
-const int kAdjustmentIntervalSeconds = 10; |
- |
-// For each period of this length we record a statistic to indicate whether |
-// or not the user experienced a low memory event. If you change this interval |
-// you must replace Tabs.Discard.DiscardInLastMinute with a new statistic. |
-const int kRecentTabDiscardIntervalSeconds = 60; |
- |
-// If there has been no priority adjustment in this interval, we assume the |
-// machine was suspended and correct our timing statistics. |
-const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; |
- |
-// When switching to a new tab the tab's renderer's OOM score needs to be |
-// updated to reflect its front-most status and protect it from discard. |
-// However, doing this immediately might slow down tab switch time, so wait |
-// a little while before doing the adjustment. |
-const int kFocusedTabScoreAdjustIntervalMs = 500; |
- |
-// Returns a unique ID for a WebContents. Do not cast back to a pointer, as |
-// the WebContents could be deleted if the user closed the tab. |
-int64 IdFromWebContents(WebContents* web_contents) { |
- return reinterpret_cast<int64>(web_contents); |
-} |
- |
-} // namespace |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-// OomPriorityManager |
- |
-OomPriorityManager::TabStats::TabStats() |
- : is_app(false), |
- is_reloadable_ui(false), |
- is_playing_audio(false), |
- is_pinned(false), |
- is_selected(false), |
- is_discarded(false), |
- renderer_handle(0), |
- tab_contents_id(0) { |
-} |
- |
-OomPriorityManager::TabStats::~TabStats() { |
-} |
- |
-OomPriorityManager::OomPriorityManager() |
- : focused_tab_process_info_(std::make_pair(0, 0)), |
- discard_count_(0), |
- recent_tab_discard_(false) { |
- // Use the old |LowMemoryObserver| when there is no |MemoryPressureMonitor|. |
- if (!base::MemoryPressureMonitor::Get()) |
- low_memory_observer_.reset(new LowMemoryObserver); |
- |
- registrar_.Add(this, |
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
- content::NotificationService::AllBrowserContextsAndSources()); |
- registrar_.Add(this, |
- content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
- content::NotificationService::AllBrowserContextsAndSources()); |
- registrar_.Add(this, |
- content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
- content::NotificationService::AllBrowserContextsAndSources()); |
-} |
- |
-OomPriorityManager::~OomPriorityManager() { |
- Stop(); |
-} |
- |
-void OomPriorityManager::Start() { |
- if (!timer_.IsRunning()) { |
- timer_.Start(FROM_HERE, |
- TimeDelta::FromSeconds(kAdjustmentIntervalSeconds), |
- this, |
- &OomPriorityManager::AdjustOomPriorities); |
- } |
- if (!recent_tab_discard_timer_.IsRunning()) { |
- recent_tab_discard_timer_.Start( |
- FROM_HERE, |
- TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds), |
- this, |
- &OomPriorityManager::RecordRecentTabDiscard); |
- } |
- start_time_ = TimeTicks::Now(); |
- // If a |LowMemoryObserver| exists we use the old system, otherwise we create |
- // a |MemoryPressureListener| to listen for memory events. |
- if (low_memory_observer_) { |
- low_memory_observer_->Start(); |
- } else { |
- base::MemoryPressureMonitor* monitor = base::MemoryPressureMonitor::Get(); |
- if (monitor) { |
- memory_pressure_listener_.reset(new base::MemoryPressureListener( |
- base::Bind(&OomPriorityManager::OnMemoryPressure, |
- base::Unretained(this)))); |
- base::MemoryPressureListener::MemoryPressureLevel level = |
- monitor->GetCurrentPressureLevel(); |
- if (level == |
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
- OnMemoryPressure(level); |
- } |
- } |
- } |
-} |
- |
-void OomPriorityManager::Stop() { |
- timer_.Stop(); |
- recent_tab_discard_timer_.Stop(); |
- if (low_memory_observer_) |
- low_memory_observer_->Stop(); |
- else |
- memory_pressure_listener_.reset(); |
-} |
- |
-std::vector<base::string16> OomPriorityManager::GetTabTitles() { |
- TabStatsList stats = GetTabStatsOnUIThread(); |
- base::AutoLock oom_score_autolock(oom_score_lock_); |
- std::vector<base::string16> titles; |
- titles.reserve(stats.size()); |
- TabStatsList::iterator it = stats.begin(); |
- for ( ; it != stats.end(); ++it) { |
- base::string16 str; |
- str.reserve(4096); |
- int score = oom_score_map_[it->child_process_host_id]; |
- str += base::IntToString16(score); |
- str += base::ASCIIToUTF16(" - "); |
- str += it->title; |
- str += base::ASCIIToUTF16(it->is_app ? " app" : ""); |
- str += base::ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : ""); |
- str += base::ASCIIToUTF16(it->is_playing_audio ? " playing_audio" : ""); |
- str += base::ASCIIToUTF16(it->is_pinned ? " pinned" : ""); |
- str += base::ASCIIToUTF16(it->is_discarded ? " discarded" : ""); |
- titles.push_back(str); |
- } |
- return titles; |
-} |
- |
-// TODO(jamescook): This should consider tabs with references to other tabs, |
-// such as tabs created with JavaScript window.open(). We might want to |
-// discard the entire set together, or use that in the priority computation. |
-bool OomPriorityManager::DiscardTab() { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- TabStatsList stats = GetTabStatsOnUIThread(); |
- if (stats.empty()) |
- return false; |
- // Loop until we find a non-discarded tab to kill. |
- for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin(); |
- stats_rit != stats.rend(); |
- ++stats_rit) { |
- int64 least_important_tab_id = stats_rit->tab_contents_id; |
- if (DiscardTabById(least_important_tab_id)) |
- return true; |
- } |
- return false; |
-} |
- |
-void OomPriorityManager::LogMemoryAndDiscardTab() { |
- LogMemory("Tab Discards Memory details", |
- base::Bind(&OomPriorityManager::PurgeMemoryAndDiscardTabs)); |
-} |
- |
-void OomPriorityManager::LogMemory(const std::string& title, |
- const base::Closure& callback) { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- OomMemoryDetails::Log(title, callback); |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// OomPriorityManager, private: |
- |
-// static |
-void OomPriorityManager::PurgeMemoryAndDiscardTabs() { |
- if (g_browser_process && |
- g_browser_process->platform_part()->oom_priority_manager()) { |
- OomPriorityManager* manager = |
- g_browser_process->platform_part()->oom_priority_manager(); |
- manager->PurgeBrowserMemory(); |
- manager->DiscardTab(); |
- } |
-} |
- |
-// static |
-bool OomPriorityManager::IsReloadableUI(const GURL& url) { |
- // There are many chrome:// UI URLs, but only look for the ones that users |
- // are likely to have open. Most of the benefit is the from NTP URL. |
- const char* const kReloadableUrlPrefixes[] = { |
- chrome::kChromeUIDownloadsURL, |
- chrome::kChromeUIHistoryURL, |
- chrome::kChromeUINewTabURL, |
- chrome::kChromeUISettingsURL, |
- }; |
- // Prefix-match against the table above. Use strncmp to avoid allocating |
- // memory to convert the URL prefix constants into std::strings. |
- for (size_t i = 0; i < arraysize(kReloadableUrlPrefixes); ++i) { |
- if (!strncmp(url.spec().c_str(), |
- kReloadableUrlPrefixes[i], |
- strlen(kReloadableUrlPrefixes[i]))) |
- return true; |
- } |
- return false; |
-} |
- |
-bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { |
- for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
- Browser* browser = *it; |
- TabStripModel* model = browser->tab_strip_model(); |
- for (int idx = 0; idx < model->count(); idx++) { |
- // Can't discard tabs that are already discarded or active. |
- if (model->IsTabDiscarded(idx) || (model->active_index() == idx)) |
- continue; |
- WebContents* web_contents = model->GetWebContentsAt(idx); |
- int64 web_contents_id = IdFromWebContents(web_contents); |
- if (web_contents_id == target_web_contents_id) { |
- LOG(WARNING) << "Discarding tab " << idx |
- << " id " << target_web_contents_id; |
- // Record statistics before discarding because we want to capture the |
- // memory state that lead to the discard. |
- RecordDiscardStatistics(); |
- model->DiscardWebContentsAt(idx); |
- recent_tab_discard_ = true; |
- return true; |
- } |
- } |
- } |
- return false; |
-} |
- |
-void OomPriorityManager::RecordDiscardStatistics() { |
- // Record a raw count so we can compare to discard reloads. |
- discard_count_++; |
- UMA_HISTOGRAM_CUSTOM_COUNTS( |
- "Tabs.Discard.DiscardCount", discard_count_, 1, 1000, 50); |
- |
- // TODO(jamescook): Maybe incorporate extension count? |
- UMA_HISTOGRAM_CUSTOM_COUNTS( |
- "Tabs.Discard.TabCount", GetTabCount(), 1, 100, 50); |
- // Record the discarded tab in relation to the amount of simultaneously |
- // logged in users. |
- ash::MultiProfileUMA::RecordDiscardedTab( |
- ash::Shell::GetInstance()->session_state_delegate()-> |
- NumberOfLoggedInUsers()); |
- |
- // TODO(jamescook): If the time stats prove too noisy, then divide up users |
- // based on how heavily they use Chrome using tab count as a proxy. |
- // Bin into <= 1, <= 2, <= 4, <= 8, etc. |
- if (last_discard_time_.is_null()) { |
- // This is the first discard this session. |
- TimeDelta interval = TimeTicks::Now() - start_time_; |
- int interval_seconds = static_cast<int>(interval.InSeconds()); |
- // Record time in seconds over an interval of approximately 1 day. |
- UMA_HISTOGRAM_CUSTOM_COUNTS( |
- "Tabs.Discard.InitialTime2", interval_seconds, 1, 100000, 50); |
- } else { |
- // Not the first discard, so compute time since last discard. |
- TimeDelta interval = TimeTicks::Now() - last_discard_time_; |
- int interval_ms = static_cast<int>(interval.InMilliseconds()); |
- // Record time in milliseconds over an interval of approximately 1 day. |
- // Start at 100 ms to get extra resolution in the target 750 ms range. |
- UMA_HISTOGRAM_CUSTOM_COUNTS( |
- "Tabs.Discard.IntervalTime2", interval_ms, 100, 100000 * 1000, 50); |
- } |
- // Record chromeos's concept of system memory usage at the time of the |
- // discard. |
- RecordMemoryStats(RECORD_MEMORY_STATS_TAB_DISCARDED); |
- |
- // Set up to record the next interval. |
- last_discard_time_ = TimeTicks::Now(); |
-} |
- |
-void OomPriorityManager::RecordRecentTabDiscard() { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- // If we change the interval we need to change the histogram name. |
- UMA_HISTOGRAM_BOOLEAN("Tabs.Discard.DiscardInLastMinute", |
- recent_tab_discard_); |
- // Reset for the next interval. |
- recent_tab_discard_ = false; |
-} |
- |
-void OomPriorityManager::PurgeBrowserMemory() { |
- // Based on experimental evidence, attempts to free memory from renderers |
- // have been too slow to use in OOM situations (V8 garbage collection) or |
- // do not lead to persistent decreased usage (image/bitmap caches). This |
- // function therefore only targets large blocks of memory in the browser. |
- // Note that other objects will listen to MemoryPressureListener events |
- // to release memory. |
- for (TabContentsIterator it; !it.done(); it.Next()) { |
- WebContents* web_contents = *it; |
- // Screenshots can consume ~5 MB per web contents for platforms that do |
- // touch back/forward. |
- web_contents->GetController().ClearAllScreenshots(); |
- } |
-} |
- |
-int OomPriorityManager::GetTabCount() const { |
- int tab_count = 0; |
- for (chrome::BrowserIterator it; !it.done(); it.Next()) |
- tab_count += it->tab_strip_model()->count(); |
- return tab_count; |
-} |
- |
-// Returns true if |first| is considered less desirable to be killed |
-// than |second|. |
-bool OomPriorityManager::CompareTabStats(TabStats first, |
- TabStats second) { |
- // Being currently selected is most important to protect. |
- if (first.is_selected != second.is_selected) |
- return first.is_selected; |
- |
- // Tab with internal web UI like NTP or Settings are good choices to discard, |
- // so protect non-Web UI and let the other conditionals finish the sort. |
- if (first.is_reloadable_ui != second.is_reloadable_ui) |
- return !first.is_reloadable_ui; |
- |
- // Being pinned is important to protect. |
- if (first.is_pinned != second.is_pinned) |
- return first.is_pinned; |
- |
- // Being an app is important too, as you're the only visible surface in the |
- // window and we don't want to discard that. |
- if (first.is_app != second.is_app) |
- return first.is_app; |
- |
- // Protect streaming audio and video conferencing tabs. |
- if (first.is_playing_audio != second.is_playing_audio) |
- return first.is_playing_audio; |
- |
- // TODO(jamescook): Incorporate sudden_termination_allowed into the sort |
- // order. We don't do this now because pages with unload handlers set |
- // sudden_termination_allowed false, and that covers too many common pages |
- // with ad networks and statistics scripts. Ideally we would like to check |
- // for beforeUnload handlers, which are likely to present a dialog asking |
- // if the user wants to discard state. crbug.com/123049 |
- |
- // Being more recently active is more important. |
- return first.last_active > second.last_active; |
-} |
- |
-void OomPriorityManager::AdjustFocusedTabScoreOnFileThread() { |
- DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- base::AutoLock oom_score_autolock(oom_score_lock_); |
- base::ProcessHandle pid = focused_tab_process_info_.second; |
- content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
- pid, chrome::kLowestRendererOomScore); |
- oom_score_map_[focused_tab_process_info_.first] = |
- chrome::kLowestRendererOomScore; |
-} |
- |
-void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { |
- BrowserThread::PostTask( |
- BrowserThread::FILE, FROM_HERE, |
- base::Bind(&OomPriorityManager::AdjustFocusedTabScoreOnFileThread, |
- base::Unretained(this))); |
-} |
- |
-void OomPriorityManager::Observe(int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- base::AutoLock oom_score_autolock(oom_score_lock_); |
- switch (type) { |
- case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: |
- case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { |
- content::RenderProcessHost* host = |
- content::Source<content::RenderProcessHost>(source).ptr(); |
- oom_score_map_.erase(host->GetID()); |
- if (!low_memory_observer_) { |
- // Coming here we know that a renderer was just killed and memory should |
- // come back into the pool. However - the memory pressure observer did |
- // not yet update its status and therefore we ask it to redo the |
- // measurement, calling us again if we have to release more. |
- // Note: We do not only accelerate the discarding speed by doing another |
- // check in short succession - we also accelerate it because the timer |
- // driven MemoryPressureMonitor will continue to produce timed events |
- // on top. So the longer the cleanup phase takes, the more tabs will |
- // get discarded in parallel. |
- base::chromeos::MemoryPressureMonitor* monitor = |
- base::chromeos::MemoryPressureMonitor::Get(); |
- if (monitor) |
- monitor->ScheduleEarlyCheck(); |
- } |
- break; |
- } |
- case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { |
- bool visible = *content::Details<bool>(details).ptr(); |
- if (visible) { |
- content::RenderProcessHost* render_host = |
- content::Source<content::RenderWidgetHost>(source).ptr()-> |
- GetProcess(); |
- focused_tab_process_info_ = std::make_pair(render_host->GetID(), |
- render_host->GetHandle()); |
- |
- // If the currently focused tab already has a lower score, do not |
- // set it. This can happen in case the newly focused tab is script |
- // connected to the previous tab. |
- ProcessScoreMap::iterator it; |
- it = oom_score_map_.find(focused_tab_process_info_.first); |
- if (it == oom_score_map_.end() |
- || it->second != chrome::kLowestRendererOomScore) { |
- // By starting a timer we guarantee that the tab is focused for |
- // certain amount of time. Secondly, it also does not add overhead |
- // to the tab switching time. |
- if (focus_tab_score_adjust_timer_.IsRunning()) |
- focus_tab_score_adjust_timer_.Reset(); |
- else |
- focus_tab_score_adjust_timer_.Start(FROM_HERE, |
- TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), |
- this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); |
- } |
- } |
- break; |
- } |
- default: |
- NOTREACHED() << L"Received unexpected notification"; |
- break; |
- } |
-} |
- |
-// Here we collect most of the information we need to sort the |
-// existing renderers in priority order, and hand out oom_score_adj |
-// scores based on that sort order. |
-// |
-// Things we need to collect on the browser thread (because |
-// TabStripModel isn't thread safe): |
-// 1) whether or not a tab is pinned |
-// 2) last time a tab was selected |
-// 3) is the tab currently selected |
-void OomPriorityManager::AdjustOomPriorities() { |
- if (BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH)->empty()) |
- return; |
- |
- // Check for a discontinuity in time caused by the machine being suspended. |
- if (!last_adjust_time_.is_null()) { |
- TimeDelta suspend_time = TimeTicks::Now() - last_adjust_time_; |
- if (suspend_time.InSeconds() > kSuspendThresholdSeconds) { |
- // We were probably suspended, move our event timers forward in time so |
- // when we subtract them out later we are counting "uptime". |
- start_time_ += suspend_time; |
- if (!last_discard_time_.is_null()) |
- last_discard_time_ += suspend_time; |
- } |
- } |
- last_adjust_time_ = TimeTicks::Now(); |
- |
- TabStatsList stats_list = GetTabStatsOnUIThread(); |
- BrowserThread::PostTask( |
- BrowserThread::FILE, FROM_HERE, |
- base::Bind(&OomPriorityManager::AdjustOomPrioritiesOnFileThread, |
- base::Unretained(this), stats_list)); |
-} |
- |
-OomPriorityManager::TabStatsList OomPriorityManager::GetTabStatsOnUIThread() { |
- DCHECK_CURRENTLY_ON(BrowserThread::UI); |
- TabStatsList stats_list; |
- stats_list.reserve(32); // 99% of users have < 30 tabs open |
- bool browser_active = true; |
- const BrowserList* ash_browser_list = |
- BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); |
- for (BrowserList::const_reverse_iterator browser_iterator = |
- ash_browser_list->begin_last_active(); |
- browser_iterator != ash_browser_list->end_last_active(); |
- ++browser_iterator) { |
- Browser* browser = *browser_iterator; |
- bool is_browser_for_app = browser->is_app(); |
- const TabStripModel* model = browser->tab_strip_model(); |
- for (int i = 0; i < model->count(); i++) { |
- WebContents* contents = model->GetWebContentsAt(i); |
- if (!contents->IsCrashed()) { |
- TabStats stats; |
- stats.is_app = is_browser_for_app; |
- stats.is_reloadable_ui = |
- IsReloadableUI(contents->GetLastCommittedURL()); |
- stats.is_playing_audio = chrome::IsPlayingAudio(contents); |
- stats.is_pinned = model->IsTabPinned(i); |
- stats.is_selected = browser_active && model->IsTabSelected(i); |
- stats.is_discarded = model->IsTabDiscarded(i); |
- stats.last_active = contents->GetLastActiveTime(); |
- stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
- stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); |
- stats.title = contents->GetTitle(); |
- stats.tab_contents_id = IdFromWebContents(contents); |
- stats_list.push_back(stats); |
- } |
- } |
- // We process the active browser window in the first iteration. |
- browser_active = false; |
- } |
- // Sort the data we collected so that least desirable to be |
- // killed is first, most desirable is last. |
- std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); |
- return stats_list; |
-} |
- |
-// static |
-std::vector<OomPriorityManager::ProcessInfo> |
- OomPriorityManager::GetChildProcessInfos( |
- const TabStatsList& stats_list) { |
- std::vector<ProcessInfo> process_infos; |
- std::set<base::ProcessHandle> already_seen; |
- for (TabStatsList::const_iterator iterator = stats_list.begin(); |
- iterator != stats_list.end(); ++iterator) { |
- // stats_list contains entries for already-discarded tabs. If the PID |
- // (renderer_handle) is zero, we don't need to adjust the oom_score. |
- if (iterator->renderer_handle == 0) |
- continue; |
- |
- bool inserted = already_seen.insert(iterator->renderer_handle).second; |
- if (!inserted) { |
- // We've already seen this process handle. |
- continue; |
- } |
- |
- process_infos.push_back(std::make_pair( |
- iterator->child_process_host_id, iterator->renderer_handle)); |
- } |
- return process_infos; |
-} |
- |
-void OomPriorityManager::AdjustOomPrioritiesOnFileThread( |
- TabStatsList stats_list) { |
- DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
- base::AutoLock oom_score_autolock(oom_score_lock_); |
- |
- // Remove any duplicate PIDs. Order of the list is maintained, so each |
- // renderer process will take on the oom_score_adj of the most important |
- // (least likely to be killed) tab. |
- std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list); |
- |
- // Now we assign priorities based on the sorted list. We're |
- // assigning priorities in the range of kLowestRendererOomScore to |
- // kHighestRendererOomScore (defined in chrome_constants.h). |
- // oom_score_adj takes values from -1000 to 1000. Negative values |
- // are reserved for system processes, and we want to give some room |
- // below the range we're using to allow for things that want to be |
- // above the renderers in priority, so the defined range gives us |
- // some variation in priority without taking up the whole range. In |
- // the end, however, it's a pretty arbitrary range to use. Higher |
- // values are more likely to be killed by the OOM killer. |
- float priority = chrome::kLowestRendererOomScore; |
- const int kPriorityRange = chrome::kHighestRendererOomScore - |
- chrome::kLowestRendererOomScore; |
- float priority_increment = |
- static_cast<float>(kPriorityRange) / process_infos.size(); |
- for (const auto& process_info : process_infos) { |
- int score = static_cast<int>(priority + 0.5f); |
- ProcessScoreMap::iterator it = |
- oom_score_map_.find(process_info.first); |
- // If a process has the same score as the newly calculated value, |
- // do not set it. |
- if (it == oom_score_map_.end() || it->second != score) { |
- content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
- process_info.second, score); |
- oom_score_map_[process_info.first] = score; |
- } |
- priority += priority_increment; |
- } |
-} |
- |
-void OomPriorityManager::OnMemoryPressure( |
- base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { |
- // For the moment we only do something when we reach a critical state. |
- if (memory_pressure_level == |
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { |
- LogMemoryAndDiscardTab(); |
- } |
- // TODO(skuhne): If more memory pressure levels are introduced, we might |
- // consider to call PurgeBrowserMemory() before CRITICAL is reached. |
-} |
- |
-} // namespace chromeos |