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: ~DiscardableMemoryManagerAllocation()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