Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      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 
      7 #include <set>
      8 
      9 #include "base/threading/thread.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/browser/history/history.h"
     12 #include "chrome/browser/profiles/profile_manager.h"
     13 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     14 #include "chrome/browser/ui/browser_list.h"
     15 #include "chrome/browser/webdata/web_data_service.h"
     16 #include "chrome/common/render_messages.h"
     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"
     21 #include "content/common/notification_service.h"
     22 #include "net/proxy/proxy_resolver.h"
     23 #include "net/url_request/url_request_context.h"
     24 #include "net/url_request/url_request_context_getter.h"
     25 #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h"
     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 
     40   void AddRequestContextGetter(
     41       scoped_refptr<net::URLRequestContextGetter> request_context_getter);
     42 
     43   void PurgeMemoryOnIOThread();
     44 
     45  private:
     46   typedef scoped_refptr<net::URLRequestContextGetter> RequestContextGetter;
     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(
     56     scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
     57   request_context_getters_.insert(request_context_getter);
     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();
     71 
     72   // The appcache service listens for this notification.
     73   NotificationService::current()->Notify(
     74       NotificationType::PURGE_MEMORY,
     75       Source<void>(NULL),
     76       NotificationService::NoDetails());
     77 }
     78 
     79 // -----------------------------------------------------------------------------
     80 
     81 // static
     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.
     89 }
     90 
     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   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
    102   for (size_t i = 0; i < profiles.size(); ++i) {
    103     purge_memory_io_helper->AddRequestContextGetter(
    104         make_scoped_refptr(profiles[i]->GetRequestContext()));
    105 
    106     // NOTE: Some objects below may be duplicates across profiles.  We could
    107     // conceivably put all these in sets and then iterate over the sets.
    108 
    109     // Unload all history backends (freeing memory used to cache sqlite).
    110     // Spinning up the history service is expensive, so we avoid doing it if it
    111     // hasn't been done already.
    112     HistoryService* history_service =
    113         profiles[i]->GetHistoryServiceWithoutCreating();
    114     if (history_service)
    115       history_service->UnloadBackend();
    116 
    117     // Unload all web databases (freeing memory used to cache sqlite).
    118     WebDataService* web_data_service =
    119         profiles[i]->GetWebDataServiceWithoutCreating();
    120     if (web_data_service)
    121       web_data_service->UnloadDatabase();
    122 
    123     // Ask all WebKitContexts to purge memory (freeing memory used to cache
    124     // the LocalStorage sqlite DB).  WebKitContext creation is basically free so
    125     // we don't bother with a "...WithoutCreating()" function.
    126     profiles[i]->GetWebKitContext()->PurgeMemory();
    127   }
    128 
    129   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    130       NewRunnableMethod(purge_memory_io_helper.get(),
    131                         &PurgeMemoryIOHelper::PurgeMemoryOnIOThread));
    132 
    133   // TODO(pkasting):
    134   // * Purge AppCache memory.  Not yet implemented sufficiently.
    135   // * Browser-side DatabaseTracker.  Not implemented sufficiently.
    136 
    137 #if (defined(OS_WIN) || defined(OS_LINUX)) && defined(USE_TCMALLOC)
    138   // Tell tcmalloc to release any free pages it's still holding.
    139   //
    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?
    143   MallocExtension::instance()->ReleaseFreeMemory();
    144 #endif
    145 }
    146 
    147 // static
    148 void MemoryPurger::PurgeRenderers() {
    149   // Direct all renderers to free everything they can.
    150   //
    151   // Concern: Telling a bunch of renderer processes to destroy their data may
    152   // cause them to page everything in to do it, which could take a lot of time/
    153   // cause jank.
    154   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
    155        !i.IsAtEnd(); i.Advance())
    156     PurgeRendererForHost(i.GetCurrentValue());
    157 }
    158 
    159 // static
    160 void MemoryPurger::PurgeRendererForHost(RenderProcessHost* host) {
    161   // Direct the renderer to free everything it can.
    162   host->Send(new ViewMsg_PurgeMemory());
    163 }
    164