Home | History | Annotate | Download | only in memory
      1 // Copyright 2014 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 #ifndef BASE_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
      6 #define BASE_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
      7 
      8 #include "base/base_export.h"
      9 #include "base/containers/hash_tables.h"
     10 #include "base/containers/mru_cache.h"
     11 #include "base/synchronization/lock.h"
     12 #include "base/time/time.h"
     13 
     14 namespace base {
     15 namespace internal {
     16 
     17 // This interface is used by the DiscardableMemoryManager class to provide some
     18 // level of userspace control over discardable memory allocations.
     19 class DiscardableMemoryManagerAllocation {
     20  public:
     21   // Allocate and acquire a lock that prevents the allocation from being purged
     22   // by the system. Returns true if memory was previously allocated and is still
     23   // resident.
     24   virtual bool AllocateAndAcquireLock() = 0;
     25 
     26   // Release a previously acquired lock on the allocation so that it can be
     27   // purged by the system.
     28   virtual void ReleaseLock() = 0;
     29 
     30   // Explicitly purge this allocation. It is illegal to call this while a lock
     31   // is acquired on the allocation.
     32   virtual void Purge() = 0;
     33 
     34  protected:
     35   virtual ~DiscardableMemoryManagerAllocation() {}
     36 };
     37 
     38 }  // namespace internal
     39 }  // namespace base
     40 
     41 #if defined(COMPILER_GCC)
     42 namespace BASE_HASH_NAMESPACE {
     43 template <>
     44 struct hash<base::internal::DiscardableMemoryManagerAllocation*> {
     45   size_t operator()(
     46       base::internal::DiscardableMemoryManagerAllocation* ptr) const {
     47     return hash<size_t>()(reinterpret_cast<size_t>(ptr));
     48   }
     49 };
     50 }  // namespace BASE_HASH_NAMESPACE
     51 #endif  // COMPILER
     52 
     53 namespace base {
     54 namespace internal {
     55 
     56 // The DiscardableMemoryManager manages a collection of
     57 // DiscardableMemoryManagerAllocation instances. It is used on platforms that
     58 // need some level of userspace control over discardable memory. It keeps track
     59 // of all allocation instances (in case they need to be purged), and the total
     60 // amount of allocated memory (in case this forces a purge). When memory usage
     61 // reaches the limit, the manager purges the LRU memory.
     62 class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
     63  public:
     64   typedef DiscardableMemoryManagerAllocation Allocation;
     65 
     66   DiscardableMemoryManager(size_t memory_limit,
     67                            size_t soft_memory_limit,
     68                            TimeDelta hard_memory_limit_expiration_time);
     69   virtual ~DiscardableMemoryManager();
     70 
     71   // The maximum number of bytes of memory that may be allocated before we force
     72   // a purge.
     73   void SetMemoryLimit(size_t bytes);
     74 
     75   // The number of bytes of memory that may be allocated but unused for the hard
     76   // limit expiration time without getting purged.
     77   void SetSoftMemoryLimit(size_t bytes);
     78 
     79   // Sets the memory usage cutoff time for hard memory limit.
     80   void SetHardMemoryLimitExpirationTime(
     81       TimeDelta hard_memory_limit_expiration_time);
     82 
     83   // This will attempt to reduce memory footprint until within soft memory
     84   // limit. Returns true if there's no need to call this again until allocations
     85   // have been used.
     86   bool ReduceMemoryUsage();
     87 
     88   // This can be called to attempt to reduce memory footprint until within
     89   // limit for bytes to keep under moderate pressure.
     90   void ReduceMemoryUsageUntilWithinLimit(size_t bytes);
     91 
     92   // Adds the given allocation to the manager's collection.
     93   void Register(Allocation* allocation, size_t bytes);
     94 
     95   // Removes the given allocation from the manager's collection.
     96   void Unregister(Allocation* allocation);
     97 
     98   // Returns false if an error occurred. Otherwise, returns true and sets
     99   // |purged| to indicate whether or not allocation has been purged since last
    100   // use.
    101   bool AcquireLock(Allocation* allocation, bool* purged);
    102 
    103   // Release a previously acquired lock on allocation. This allows the manager
    104   // to purge it if necessary.
    105   void ReleaseLock(Allocation* allocation);
    106 
    107   // Purges all discardable memory.
    108   void PurgeAll();
    109 
    110   // Returns true if allocation has been added to the manager's collection. This
    111   // should only be used by tests.
    112   bool IsRegisteredForTest(Allocation* allocation) const;
    113 
    114   // Returns true if allocation can be purged. This should only be used by
    115   // tests.
    116   bool CanBePurgedForTest(Allocation* allocation) const;
    117 
    118   // Returns total amount of allocated discardable memory. This should only be
    119   // used by tests.
    120   size_t GetBytesAllocatedForTest() const;
    121 
    122  private:
    123   struct AllocationInfo {
    124     explicit AllocationInfo(size_t bytes) : bytes(bytes), purgable(false) {}
    125 
    126     const size_t bytes;
    127     bool purgable;
    128     TimeTicks last_usage;
    129   };
    130   typedef HashingMRUCache<Allocation*, AllocationInfo> AllocationMap;
    131 
    132   // Purges memory not used since |hard_memory_limit_expiration_time_| before
    133   // "right now" until usage is less or equal to |soft_memory_limit_|.
    134   // Returns true if total amount of memory is less or equal to soft memory
    135   // limit.
    136   bool PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
    137 
    138   // Purges memory that has not been used since |timestamp| until usage is less
    139   // or equal to |limit|.
    140   // Caller must acquire |lock_| prior to calling this function.
    141   void PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
    142       TimeTicks timestamp,
    143       size_t limit);
    144 
    145   // Called when a change to |bytes_allocated_| has been made.
    146   void BytesAllocatedChanged(size_t new_bytes_allocated) const;
    147 
    148   // Virtual for tests.
    149   virtual TimeTicks Now() const;
    150 
    151   // Needs to be held when accessing members.
    152   mutable Lock lock_;
    153 
    154   // A MRU cache of all allocated bits of memory. Used for purging.
    155   AllocationMap allocations_;
    156 
    157   // The total amount of allocated memory.
    158   size_t bytes_allocated_;
    159 
    160   // The maximum number of bytes of memory that may be allocated.
    161   size_t memory_limit_;
    162 
    163   // The number of bytes of memory that may be allocated but not used for
    164   // |hard_memory_limit_expiration_time_| amount of time when receiving an idle
    165   // notification.
    166   size_t soft_memory_limit_;
    167 
    168   // Amount of time it takes for an allocation to become affected by
    169   // |soft_memory_limit_|.
    170   TimeDelta hard_memory_limit_expiration_time_;
    171 
    172   DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryManager);
    173 };
    174 
    175 }  // namespace internal
    176 }  // namespace base
    177 
    178 #endif  // BASE_MEMORY_DISCARDABLE_MEMORY_MANAGER_H_
    179