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