15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/memory_purger.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/allocator/allocator_extension.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service_factory.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/webdata/web_data_service.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/webdata/web_data_service_factory.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/render_messages.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_context.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_resolver.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_service.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserContext; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::ResourceContext; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PurgeMemoryHelper ----------------------------------------------------------- 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is a small helper class used to ensure that the objects we want to use 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on multiple threads are properly refed, so they don't get deleted out from 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// under us. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PurgeMemoryIOHelper 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<PurgeMemoryIOHelper> { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PurgeMemoryIOHelper() { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) safe_browsing_service_ = g_browser_process->safe_browsing_service(); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddRequestContextGetter( 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<net::URLRequestContextGetter> request_context_getter); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PurgeMemoryOnIOThread(); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<PurgeMemoryIOHelper>; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~PurgeMemoryIOHelper() {} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<RequestContextGetter> request_context_getters_; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<SafeBrowsingService> safe_browsing_service_; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(PurgeMemoryIOHelper); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PurgeMemoryIOHelper::AddRequestContextGetter( 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<net::URLRequestContextGetter> request_context_getter) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getters_.push_back(request_context_getter); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PurgeMemoryIOHelper::PurgeMemoryOnIOThread() { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ask ProxyServices to purge any memory they can (generally garbage in the 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wrapped ProxyResolver's JS engine). 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < request_context_getters_.size(); ++i) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_context_getters_[i]->GetURLRequestContext()->proxy_service()-> 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PurgeMemory(); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(FULL_SAFE_BROWSING) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) safe_browsing_service_->database_manager()->PurgeMemory(); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeAll() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PurgeBrowser(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PurgeRenderers(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(pkasting): 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Tell the plugin processes to release their free memory? Other stuff? 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Enumerate what other processes exist and what to do for them. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeBrowser() { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Dump the backing stores. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderWidgetHost::RemoveAllBackingStores(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Per-profile cleanup. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<PurgeMemoryIOHelper> purge_memory_io_helper( 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new PurgeMemoryIOHelper()); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileManager* profile_manager = g_browser_process->profile_manager(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < profiles.size(); ++i) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) purge_memory_io_helper->AddRequestContextGetter( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_scoped_refptr(profiles[i]->GetRequestContext())); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: Some objects below may be duplicates across profiles. We could 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // conceivably put all these in sets and then iterate over the sets. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unload all history backends (freeing memory used to cache sqlite). 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Spinning up the history service is expensive, so we avoid doing it if it 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hasn't been done already. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryService* history_service = 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryServiceFactory::GetForProfileWithoutCreating(profiles[i]); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (history_service) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_service->UnloadBackend(); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unload all web databases (freeing memory used to cache sqlite). 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebDataServiceWrapper* wds_wrapper = 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebDataServiceFactory::GetForProfileIfExists( 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiles[i], Profile::EXPLICIT_ACCESS); 1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (wds_wrapper && wds_wrapper->GetWebData().get()) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wds_wrapper->GetWebData()->UnloadDatabase(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserContext::PurgeMemory(profiles[i]); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::IO, FROM_HERE, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&PurgeMemoryIOHelper::PurgeMemoryOnIOThread, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) purge_memory_io_helper.get())); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(pkasting): 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Purge AppCache memory. Not yet implemented sufficiently. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Browser-side DatabaseTracker. Not implemented sufficiently. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Tell our allocator to release any free pages it's still holding. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(pkasting): A lot of the above calls kick off actions on other threads. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Maybe we should find a way to avoid calling this until those actions 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // complete? 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::allocator::ReleaseFreeMemory(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeRenderers() { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Direct all renderers to free everything they can. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Concern: Telling a bunch of renderer processes to destroy their data may 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cause them to page everything in to do it, which could take a lot of time/ 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cause jank. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (content::RenderProcessHost::iterator i( 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderProcessHost::AllHostsIterator()); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !i.IsAtEnd(); i.Advance()) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PurgeRendererForHost(i.GetCurrentValue()); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryPurger::PurgeRendererForHost(content::RenderProcessHost* host) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Direct the renderer to free everything it can. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host->Send(new ChromeViewMsg_PurgeMemory()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 164