[email protected] | b3841c50 | 2011-03-09 01:21:31 | [diff] [blame] | 1 | // Copyright (c) 2011 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] | 34b9963 | 2011-01-01 01:01:06 | [diff] [blame] | 9 | #include "base/threading/thread.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 10 | #include "chrome/browser/browser_list.h" |
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] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 14 | #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
15 | #include "chrome/browser/webdata/web_data_service.h" | ||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 16 | #include "chrome/common/render_messages.h" |
[email protected] | 567812d | 2011-02-24 17:40:50 | [diff] [blame] | 17 | #include "content/browser/in_process_webkit/webkit_context.h" |
18 | #include "content/browser/renderer_host/backing_store_manager.h" | ||||
19 | #include "content/browser/renderer_host/render_process_host.h" | ||||
20 | #include "content/browser/renderer_host/resource_dispatcher_host.h" | ||||
[email protected] | b3841c50 | 2011-03-09 01:21:31 | [diff] [blame] | 21 | #include "content/common/notification_service.h" |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 22 | #include "net/proxy/proxy_resolver.h" |
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 | #include "v8/include/v8.h" |
27 | |||||
28 | // PurgeMemoryHelper ----------------------------------------------------------- | ||||
29 | |||||
30 | // This is a small helper class used to ensure that the objects we want to use | ||||
31 | // on multiple threads are properly refed, so they don't get deleted out from | ||||
32 | // under us. | ||||
33 | class PurgeMemoryIOHelper | ||||
34 | : public base::RefCountedThreadSafe<PurgeMemoryIOHelper> { | ||||
35 | public: | ||||
36 | explicit PurgeMemoryIOHelper(SafeBrowsingService* safe_browsing_service) | ||||
37 | : safe_browsing_service_(safe_browsing_service) { | ||||
38 | } | ||||
39 | |||||
[email protected] | 00cd9c4 | 2010-11-02 20:15:57 | [diff] [blame] | 40 | void AddRequestContextGetter( |
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame^] | 41 | scoped_refptr<net::URLRequestContextGetter> request_context_getter); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 42 | |
43 | void PurgeMemoryOnIOThread(); | ||||
44 | |||||
45 | private: | ||||
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame^] | 46 | typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter; |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 47 | typedef std::set<RequestContextGetter> RequestContextGetters; |
48 | |||||
49 | RequestContextGetters request_context_getters_; | ||||
50 | scoped_refptr<SafeBrowsingService> safe_browsing_service_; | ||||
51 | |||||
52 | DISALLOW_COPY_AND_ASSIGN(PurgeMemoryIOHelper); | ||||
53 | }; | ||||
54 | |||||
55 | void PurgeMemoryIOHelper::AddRequestContextGetter( | ||||
[email protected] | abe2c03 | 2011-03-31 18:49:34 | [diff] [blame^] | 56 | scoped_refptr<net::URLRequestContextGetter> request_context_getter) { |
[email protected] | 00cd9c4 | 2010-11-02 20:15:57 | [diff] [blame] | 57 | request_context_getters_.insert(request_context_getter); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 58 | } |
59 | |||||
60 | void PurgeMemoryIOHelper::PurgeMemoryOnIOThread() { | ||||
61 | // Ask ProxyServices to purge any memory they can (generally garbage in the | ||||
62 | // wrapped ProxyResolver's JS engine). | ||||
63 | for (RequestContextGetters::const_iterator i( | ||||
64 | request_context_getters_.begin()); | ||||
65 | i != request_context_getters_.end(); ++i) | ||||
66 | (*i)->GetURLRequestContext()->proxy_service()->PurgeMemory(); | ||||
67 | |||||
68 | // Close the Safe Browsing database, freeing memory used to cache sqlite as | ||||
69 | // well as a number of in-memory structures. | ||||
70 | safe_browsing_service_->CloseDatabase(); | ||||
[email protected] | 520cdd7 | 2010-01-13 22:14:46 | [diff] [blame] | 71 | |
72 | // The appcache service listens for this notification. | ||||
73 | NotificationService::current()->Notify( | ||||
74 | NotificationType::PURGE_MEMORY, | ||||
75 | Source<void>(NULL), | ||||
76 | NotificationService::NoDetails()); | ||||
[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. | ||||
94 | BackingStoreManager::RemoveAllBackingStores(); | ||||
95 | |||||
96 | // Per-profile cleanup. | ||||
97 | scoped_refptr<PurgeMemoryIOHelper> purge_memory_io_helper( | ||||
98 | new PurgeMemoryIOHelper(g_browser_process->resource_dispatcher_host()-> | ||||
99 | safe_browsing_service())); | ||||
100 | ProfileManager* profile_manager = g_browser_process->profile_manager(); | ||||
101 | for (ProfileManager::iterator i(profile_manager->begin()); | ||||
102 | i != profile_manager->end(); ++i) { | ||||
103 | Profile* profile = *i; | ||||
104 | purge_memory_io_helper->AddRequestContextGetter( | ||||
[email protected] | 00cd9c4 | 2010-11-02 20:15:57 | [diff] [blame] | 105 | make_scoped_refptr(profile->GetRequestContext())); |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 106 | |
107 | // NOTE: Some objects below may be duplicates across profiles. We could | ||||
108 | // conceivably put all these in sets and then iterate over the sets. | ||||
109 | |||||
110 | // Unload all history backends (freeing memory used to cache sqlite). | ||||
111 | // Spinning up the history service is expensive, so we avoid doing it if it | ||||
112 | // hasn't been done already. | ||||
113 | HistoryService* history_service = | ||||
114 | profile->GetHistoryServiceWithoutCreating(); | ||||
115 | if (history_service) | ||||
116 | history_service->UnloadBackend(); | ||||
117 | |||||
118 | // Unload all web databases (freeing memory used to cache sqlite). | ||||
119 | WebDataService* web_data_service = | ||||
120 | profile->GetWebDataServiceWithoutCreating(); | ||||
121 | if (web_data_service) | ||||
122 | web_data_service->UnloadDatabase(); | ||||
123 | |||||
124 | // Ask all WebKitContexts to purge memory (freeing memory used to cache | ||||
125 | // the LocalStorage sqlite DB). WebKitContext creation is basically free so | ||||
126 | // we don't bother with a "...WithoutCreating()" function. | ||||
127 | profile->GetWebKitContext()->PurgeMemory(); | ||||
128 | } | ||||
129 | |||||
[email protected] | f8b3ef8 | 2010-10-11 02:45:52 | [diff] [blame] | 130 | BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 131 | NewRunnableMethod(purge_memory_io_helper.get(), |
132 | &PurgeMemoryIOHelper::PurgeMemoryOnIOThread)); | ||||
133 | |||||
134 | // TODO(pkasting): | ||||
135 | // * Purge AppCache memory. Not yet implemented sufficiently. | ||||
136 | // * Browser-side DatabaseTracker. Not implemented sufficiently. | ||||
137 | |||||
[email protected] | 61a9b2d8 | 2010-02-26 00:31:08 | [diff] [blame] | 138 | #if (defined(OS_WIN) || defined(OS_LINUX)) && defined(USE_TCMALLOC) |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 139 | // Tell tcmalloc to release any free pages it's still holding. |
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 140 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 141 | // TODO(pkasting): A lot of the above calls kick off actions on other threads. |
142 | // Maybe we should find a way to avoid calling this until those actions | ||||
143 | // complete? | ||||
144 | MallocExtension::instance()->ReleaseFreeMemory(); | ||||
145 | #endif | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 146 | } |
147 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 148 | // static |
149 | void MemoryPurger::PurgeRenderers() { | ||||
150 | // Direct all renderers to free everything they can. | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 151 | // |
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 152 | // Concern: Telling a bunch of renderer processes to destroy their data may |
153 | // cause them to page everything in to do it, which could take a lot of time/ | ||||
154 | // cause jank. | ||||
155 | for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | ||||
156 | !i.IsAtEnd(); i.Advance()) | ||||
157 | PurgeRendererForHost(i.GetCurrentValue()); | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 158 | } |
159 | |||||
[email protected] | 3148c5d | 2009-11-18 19:32:58 | [diff] [blame] | 160 | // static |
161 | void MemoryPurger::PurgeRendererForHost(RenderProcessHost* host) { | ||||
162 | // Direct the renderer to free everything it can. | ||||
163 | host->Send(new ViewMsg_PurgeMemory()); | ||||
[email protected] | 0dd5dda0 | 2009-10-01 18:50:19 | [diff] [blame] | 164 | } |