[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] | 567812d | 2011-02-24 17:40:50 | [diff] [blame] | 18 | #include "content/browser/renderer_host/backing_store_manager.h" |
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 19 | #include "content/public/browser/render_process_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] | 1b1f3eb | 2009-12-01 13:48:04 | [diff] [blame] | 25 | #include "third_party/tcmalloc/chromium/src/google/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 | |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 46 | void PurgeMemoryOnIOThread(); |
47 | |||||
48 | private: | ||||
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame] | 49 | typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter; |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 50 | |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 51 | std::vector<RequestContextGetter> request_context_getters_; |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 52 | scoped_refptr<SafeBrowsingService> safe_browsing_service_; |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 53 | |
54 | DISALLOW_COPY_AND_ASSIGN(PurgeMemoryIOHelper); | ||||
55 | }; | ||||
56 | |||||
57 | void PurgeMemoryIOHelper::AddRequestContextGetter( | ||||
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame] | 58 | scoped_refptr<net::URLRequestContextGetter> request_context_getter) { |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 59 | request_context_getters_.push_back(request_context_getter); |
60 | } | ||||
61 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 62 | void PurgeMemoryIOHelper::PurgeMemoryOnIOThread() { |
63 | // Ask ProxyServices to purge any memory they can (generally garbage in the | ||||
64 | // wrapped ProxyResolver's JS engine). | ||||
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 65 | for (size_t i = 0; i < request_context_getters_.size(); ++i) { |
66 | request_context_getters_[i]->GetURLRequestContext()->proxy_service()-> | ||||
67 | PurgeMemory(); | ||||
68 | } | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 69 | |
[email protected] | 1962a9c | 2012-02-21 21:56:15 | [diff] [blame] | 70 | safe_browsing_service_->PurgeMemory(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 71 | } |
72 | |||||
73 | // ----------------------------------------------------------------------------- | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 74 | |
75 | // static | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 76 | void MemoryPurger::PurgeAll() { |
77 | PurgeBrowser(); | ||||
78 | PurgeRenderers(); | ||||
79 | |||||
80 | // TODO(pkasting): | ||||
81 | // * Tell the plugin processes to release their free memory? Other stuff? | ||||
82 | // * Enumerate what other processes exist and what to do for them. | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 83 | } |
84 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 85 | // static |
86 | void MemoryPurger::PurgeBrowser() { | ||||
87 | // Dump the backing stores. | ||||
88 | BackingStoreManager::RemoveAllBackingStores(); | ||||
89 | |||||
90 | // Per-profile cleanup. | ||||
91 | scoped_refptr<PurgeMemoryIOHelper> purge_memory_io_helper( | ||||
[email protected] | b864a41 | 2011-07-07 10:51:48 | [diff] [blame] | 92 | new PurgeMemoryIOHelper()); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 93 | ProfileManager* profile_manager = g_browser_process->profile_manager(); |
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 94 | std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); |
95 | for (size_t i = 0; i < profiles.size(); ++i) { | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 96 | purge_memory_io_helper->AddRequestContextGetter( |
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 97 | make_scoped_refptr(profiles[i]->GetRequestContext())); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 98 | |
99 | // NOTE: Some objects below may be duplicates across profiles. We could | ||||
100 | // conceivably put all these in sets and then iterate over the sets. | ||||
101 | |||||
102 | // Unload all history backends (freeing memory used to cache sqlite). | ||||
103 | // Spinning up the history service is expensive, so we avoid doing it if it | ||||
104 | // hasn't been done already. | ||||
105 | HistoryService* history_service = | ||||
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 106 | profiles[i]->GetHistoryServiceWithoutCreating(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 107 | if (history_service) |
108 | history_service->UnloadBackend(); | ||||
109 | |||||
110 | // Unload all web databases (freeing memory used to cache sqlite). | ||||
111 | WebDataService* web_data_service = | ||||
[email protected] | 844a100 | 2011-04-19 11:37:21 | [diff] [blame] | 112 | profiles[i]->GetWebDataServiceWithoutCreating(); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 113 | if (web_data_service) |
114 | web_data_service->UnloadDatabase(); | ||||
115 | |||||
[email protected] | 6e2d3d2 | 2012-02-24 18:10:36 | [diff] [blame^] | 116 | BrowserContext::PurgeMemory(profiles[i]); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 117 | } |
118 | |||||
[email protected] | 24d6969 | 2011-10-21 18:26:51 | [diff] [blame] | 119 | BrowserThread::PostTask( |
120 | BrowserThread::IO, FROM_HERE, | ||||
121 | base::Bind(&PurgeMemoryIOHelper::PurgeMemoryOnIOThread, | ||||
122 | purge_memory_io_helper.get())); | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 123 | |
124 | // TODO(pkasting): | ||||
125 | // * Purge AppCache memory. Not yet implemented sufficiently. | ||||
126 | // * Browser-side DatabaseTracker. Not implemented sufficiently. | ||||
127 | |||||
[email protected] | 1fd5302c | 2011-05-28 04:06:43 | [diff] [blame] | 128 | #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 129 | // Tell tcmalloc to release any free pages it's still holding. |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 130 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 131 | // TODO(pkasting): A lot of the above calls kick off actions on other threads. |
132 | // Maybe we should find a way to avoid calling this until those actions | ||||
133 | // complete? | ||||
134 | MallocExtension::instance()->ReleaseFreeMemory(); | ||||
135 | #endif | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 136 | } |
137 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 138 | // static |
139 | void MemoryPurger::PurgeRenderers() { | ||||
140 | // Direct all renderers to free everything they can. | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 141 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 142 | // Concern: Telling a bunch of renderer processes to destroy their data may |
143 | // cause them to page everything in to do it, which could take a lot of time/ | ||||
144 | // cause jank. | ||||
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 145 | for (content::RenderProcessHost::iterator i( |
146 | content::RenderProcessHost::AllHostsIterator()); | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 147 | !i.IsAtEnd(); i.Advance()) |
148 | PurgeRendererForHost(i.GetCurrentValue()); | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 149 | } |
150 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 151 | // static |
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 152 | void MemoryPurger::PurgeRendererForHost(content::RenderProcessHost* host) { |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 153 | // Direct the renderer to free everything it can. |
[email protected] | 2ccf45c | 2011-08-19 23:35:50 | [diff] [blame] | 154 | host->Send(new ChromeViewMsg_PurgeMemory()); |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 155 | } |