[email protected] | 6b4329a | 2012-01-25 10:51:28 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. | ||||
4 | |||||
5 | #include "chrome/browser/memory_purger.h" | ||||
6 | |||||
[email protected] | 61a9b2d8 | 2010-02-26 00:31:08 | [diff] [blame] | 7 | #include <set> |
8 | |||||
[email protected] | 24d6969 | 2011-10-21 18:26:51 | [diff] [blame] | 9 | #include "base/bind.h" |
[email protected] | 34b9963 | 2011-01-01 01:01:06 | [diff] [blame] | 10 | #include "base/threading/thread.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 11 | #include "chrome/browser/browser_process.h" |
12 | #include "chrome/browser/history/history.h" | ||||
[email protected] | 8ecad5e | 2010-12-02 21:18:33 | [diff] [blame] | 13 | #include "chrome/browser/profiles/profile_manager.h" |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 14 | #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
[email protected] | 71b73f0 | 2011-04-06 15:57:29 | [diff] [blame] | 15 | #include "chrome/browser/ui/browser_list.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 16 | #include "chrome/browser/webdata/web_data_service.h" |
17 | #include "chrome/common/render_messages.h" | ||||
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 18 | #include "content/public/browser/render_process_host.h" |
[email protected] | 9c1662b | 2012-03-06 15:44:33 | [diff] [blame] | 19 | #include "content/public/browser/render_widget_host.h" |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 20 | #include "content/public/browser/resource_context.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 21 | #include "net/proxy/proxy_resolver.h" |
[email protected] | 6104ea5d | 2011-04-27 21:37:12 | [diff] [blame] | 22 | #include "net/proxy/proxy_service.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 23 | #include "net/url_request/url_request_context.h" |
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame] | 24 | #include "net/url_request/url_request_context_getter.h" |
[email protected] | 451c89d6 | 2012-03-13 17:13:00 | [diff] [blame] | 25 | #include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 26 | |
[email protected] | 55eb70e76 | 2012-02-20 17:38:39 | [diff] [blame] | 27 | using content::BrowserContext; |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 28 | using content::BrowserThread; |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 29 | using content::ResourceContext; |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 30 | |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 31 | // PurgeMemoryHelper ----------------------------------------------------------- |
32 | |||||
33 | // This is a small helper class used to ensure that the objects we want to use | ||||
34 | // on multiple threads are properly refed, so they don't get deleted out from | ||||
35 | // under us. | ||||
36 | class PurgeMemoryIOHelper | ||||
37 | : public base::RefCountedThreadSafe<PurgeMemoryIOHelper> { | ||||
38 | public: | ||||
[email protected] | b864a41 | 2011-07-07 10:51:48 | [diff] [blame] | 39 | PurgeMemoryIOHelper() { |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 40 | safe_browsing_service_ = g_browser_process->safe_browsing_service(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 41 | } |
42 | |||||
[email protected] | 00cd9c4 | 2010-11-02 20:15:57 | [diff] [blame] | 43 | void AddRequestContextGetter( |
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame] | 44 | scoped_refptr<net::URLRequestContextGetter> request_context_getter); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 45 | |
46 | void PurgeMemoryOnIOThread(); | ||||
47 | |||||
48 | private: | ||||
[email protected] | 649d1c0 | 2012-04-27 02:56:21 | [diff] [blame^] | 49 | friend class base::RefCountedThreadSafe<PurgeMemoryIOHelper>; |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 50 | |
[email protected] | 649d1c0 | 2012-04-27 02:56:21 | [diff] [blame^] | 51 | virtual ~PurgeMemoryIOHelper() {} |
52 | |||||
53 | typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter; | ||||
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 54 | std::vector<RequestContextGetter> request_context_getters_; |
[email protected] | 649d1c0 | 2012-04-27 02:56:21 | [diff] [blame^] | 55 | |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 56 | scoped_refptr<SafeBrowsingService> safe_browsing_service_; |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 57 | |
58 | DISALLOW_COPY_AND_ASSIGN(PurgeMemoryIOHelper); | ||||
59 | }; | ||||
60 | |||||
61 | void PurgeMemoryIOHelper::AddRequestContextGetter( | ||||
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame] | 62 | scoped_refptr<net::URLRequestContextGetter> request_context_getter) { |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 63 | request_context_getters_.push_back(request_context_getter); |
64 | } | ||||
65 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 66 | void PurgeMemoryIOHelper::PurgeMemoryOnIOThread() { |
67 | // Ask ProxyServices to purge any memory they can (generally garbage in the | ||||
68 | // wrapped ProxyResolver's JS engine). | ||||
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 69 | for (size_t i = 0; i < request_context_getters_.size(); ++i) { |
70 | request_context_getters_[i]->GetURLRequestContext()->proxy_service()-> | ||||
71 | PurgeMemory(); | ||||
72 | } | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 73 | |
[email protected] | 69c87ac | 2012-03-28 19:38:30 | [diff] [blame] | 74 | #if defined(ENABLE_SAFE_BROWSING) |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 75 | safe_browsing_service_->PurgeMemory(); |
[email protected] | 69c87ac | 2012-03-28 19:38:30 | [diff] [blame] | 76 | #endif |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 77 | } |
78 | |||||
79 | // ----------------------------------------------------------------------------- | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 80 | |
81 | // static | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 82 | void MemoryPurger::PurgeAll() { |
83 | PurgeBrowser(); | ||||
84 | PurgeRenderers(); | ||||
85 | |||||
86 | // TODO(pkasting): | ||||
87 | // * Tell the plugin processes to release their free memory? Other stuff? | ||||
88 | // * Enumerate what other processes exist and what to do for them. | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 89 | } |
90 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 91 | // static |
92 | void MemoryPurger::PurgeBrowser() { | ||||
93 | // Dump the backing stores. | ||||
[email protected] | eaabba2 | 2012-03-07 15:02:11 | [diff] [blame] | 94 | content::RenderWidgetHost::RemoveAllBackingStores(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 95 | |
96 | // Per-profile cleanup. | ||||
97 | scoped_refptr<PurgeMemoryIOHelper> purge_memory_io_helper( | ||||
[email protected] | b864a41 | 2011-07-07 10:51:48 | [diff] [blame] | 98 | new PurgeMemoryIOHelper()); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 99 | ProfileManager* profile_manager = g_browser_process->profile_manager(); |
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 100 | std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); |
101 | for (size_t i = 0; i < profiles.size(); ++i) { | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 102 | purge_memory_io_helper->AddRequestContextGetter( |
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 103 | make_scoped_refptr(profiles[i]->GetRequestContext())); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 104 | |
105 | // NOTE: Some objects below may be duplicates across profiles. We could | ||||
106 | // conceivably put all these in sets and then iterate over the sets. | ||||
107 | |||||
108 | // Unload all history backends (freeing memory used to cache sqlite). | ||||
109 | // Spinning up the history service is expensive, so we avoid doing it if it | ||||
110 | // hasn't been done already. | ||||
111 | HistoryService* history_service = | ||||
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 112 | profiles[i]->GetHistoryServiceWithoutCreating(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 113 | if (history_service) |
114 | history_service->UnloadBackend(); | ||||
115 | |||||
116 | // Unload all web databases (freeing memory used to cache sqlite). | ||||
117 | WebDataService* web_data_service = | ||||
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 118 | profiles[i]->GetWebDataServiceWithoutCreating(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 119 | if (web_data_service) |
120 | web_data_service->UnloadDatabase(); | ||||
121 | |||||
[email protected] | 6e2d3d2 | 2012-02-24 18:10:36 | [diff] [blame] | 122 | BrowserContext::PurgeMemory(profiles[i]); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 123 | } |
124 | |||||
[email protected] | 24d6969 | 2011-10-21 18:26:51 | [diff] [blame] | 125 | BrowserThread::PostTask( |
126 | BrowserThread::IO, FROM_HERE, | ||||
127 | base::Bind(&PurgeMemoryIOHelper::PurgeMemoryOnIOThread, | ||||
128 | purge_memory_io_helper.get())); | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 129 | |
130 | // TODO(pkasting): | ||||
131 | // * Purge AppCache memory. Not yet implemented sufficiently. | ||||
132 | // * Browser-side DatabaseTracker. Not implemented sufficiently. | ||||
133 | |||||
[email protected] | 1fd5302c | 2011-05-28 04:06:43 | [diff] [blame] | 134 | #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 135 | // Tell tcmalloc to release any free pages it's still holding. |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 136 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 137 | // TODO(pkasting): A lot of the above calls kick off actions on other threads. |
138 | // Maybe we should find a way to avoid calling this until those actions | ||||
139 | // complete? | ||||
140 | MallocExtension::instance()->ReleaseFreeMemory(); | ||||
141 | #endif | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 142 | } |
143 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 144 | // static |
145 | void MemoryPurger::PurgeRenderers() { | ||||
146 | // Direct all renderers to free everything they can. | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 147 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 148 | // Concern: Telling a bunch of renderer processes to destroy their data may |
149 | // cause them to page everything in to do it, which could take a lot of time/ | ||||
150 | // cause jank. | ||||
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 151 | for (content::RenderProcessHost::iterator i( |
152 | content::RenderProcessHost::AllHostsIterator()); | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 153 | !i.IsAtEnd(); i.Advance()) |
154 | PurgeRendererForHost(i.GetCurrentValue()); | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 155 | } |
156 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 157 | // static |
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 158 | void MemoryPurger::PurgeRendererForHost(content::RenderProcessHost* host) { |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 159 | // Direct the renderer to free everything it can. |
[email protected] | 2ccf45c | 2011-08-19 23:35:50 | [diff] [blame] | 160 | host->Send(new ChromeViewMsg_PurgeMemory()); |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 161 | } |