Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: base/memory/discardable_memory_manager.cc

Issue 336273003: base: Add soft memory limit to DiscardableMemoryManager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix typo in comment Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/discardable_memory_manager.h" 5 #include "base/memory/discardable_memory_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/containers/hash_tables.h" 8 #include "base/containers/hash_tables.h"
9 #include "base/containers/mru_cache.h" 9 #include "base/containers/mru_cache.h"
10 #include "base/debug/crash_logging.h" 10 #include "base/debug/crash_logging.h"
11 #include "base/debug/trace_event.h" 11 #include "base/debug/trace_event.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/synchronization/lock.h" 13 #include "base/synchronization/lock.h"
14 14
15 namespace base { 15 namespace base {
16 namespace internal { 16 namespace internal {
17 17
18 DiscardableMemoryManager::DiscardableMemoryManager( 18 DiscardableMemoryManager::DiscardableMemoryManager(
19 size_t memory_limit, 19 size_t memory_limit,
20 size_t bytes_to_keep_under_moderate_pressure) 20 size_t soft_memory_limit,
21 size_t bytes_to_keep_under_moderate_pressure,
22 TimeDelta hard_memory_limit_expiration_time)
21 : allocations_(AllocationMap::NO_AUTO_EVICT), 23 : allocations_(AllocationMap::NO_AUTO_EVICT),
22 bytes_allocated_(0), 24 bytes_allocated_(0u),
23 memory_limit_(memory_limit), 25 memory_limit_(memory_limit),
26 soft_memory_limit_(soft_memory_limit),
24 bytes_to_keep_under_moderate_pressure_( 27 bytes_to_keep_under_moderate_pressure_(
25 bytes_to_keep_under_moderate_pressure) { 28 bytes_to_keep_under_moderate_pressure),
26 BytesAllocatedChanged(); 29 hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
30 BytesAllocatedChanged(bytes_allocated_);
27 } 31 }
28 32
29 DiscardableMemoryManager::~DiscardableMemoryManager() { 33 DiscardableMemoryManager::~DiscardableMemoryManager() {
30 DCHECK(allocations_.empty()); 34 DCHECK(allocations_.empty());
31 DCHECK_EQ(0u, bytes_allocated_); 35 DCHECK_EQ(0u, bytes_allocated_);
32 } 36 }
33 37
34 void DiscardableMemoryManager::RegisterMemoryPressureListener() { 38 void DiscardableMemoryManager::RegisterMemoryPressureListener() {
35 AutoLock lock(lock_); 39 AutoLock lock(lock_);
36 DCHECK(base::MessageLoop::current()); 40 DCHECK(base::MessageLoop::current());
37 DCHECK(!memory_pressure_listener_); 41 DCHECK(!memory_pressure_listener_);
38 memory_pressure_listener_.reset(new MemoryPressureListener(base::Bind( 42 memory_pressure_listener_.reset(new MemoryPressureListener(base::Bind(
39 &DiscardableMemoryManager::OnMemoryPressure, Unretained(this)))); 43 &DiscardableMemoryManager::OnMemoryPressure, Unretained(this))));
40 } 44 }
41 45
42 void DiscardableMemoryManager::UnregisterMemoryPressureListener() { 46 void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
43 AutoLock lock(lock_); 47 AutoLock lock(lock_);
44 DCHECK(memory_pressure_listener_); 48 DCHECK(memory_pressure_listener_);
45 memory_pressure_listener_.reset(); 49 memory_pressure_listener_.reset();
46 } 50 }
47 51
48 void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) { 52 void DiscardableMemoryManager::SetMemoryLimit(size_t bytes) {
49 AutoLock lock(lock_); 53 AutoLock lock(lock_);
50 memory_limit_ = bytes; 54 memory_limit_ = bytes;
51 EnforcePolicyWithLockAcquired(); 55 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
56 Now(), memory_limit_);
57 }
58
59 void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
60 AutoLock lock(lock_);
61 soft_memory_limit_ = bytes;
52 } 62 }
53 63
54 void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure( 64 void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
55 size_t bytes) { 65 size_t bytes) {
56 AutoLock lock(lock_); 66 AutoLock lock(lock_);
57 bytes_to_keep_under_moderate_pressure_ = bytes; 67 bytes_to_keep_under_moderate_pressure_ = bytes;
58 } 68 }
59 69
70 void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
71 TimeDelta hard_memory_limit_expiration_time) {
72 AutoLock lock(lock_);
73 hard_memory_limit_expiration_time_ = hard_memory_limit_expiration_time;
74 }
75
76 bool DiscardableMemoryManager::IdleNotification() {
77 return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
78 }
79
60 void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) { 80 void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
61 AutoLock lock(lock_); 81 AutoLock lock(lock_);
62 // A registered memory listener is currently required. This DCHECK can be 82 // A registered memory listener is currently required. This DCHECK can be
63 // moved or removed if we decide that it's useful to relax this condition. 83 // moved or removed if we decide that it's useful to relax this condition.
64 // TODO(reveman): Enable this DCHECK when skia and blink are able to 84 // TODO(reveman): Enable this DCHECK when skia and blink are able to
65 // register memory pressure listeners. crbug.com/333907 85 // register memory pressure listeners. crbug.com/333907
66 // DCHECK(memory_pressure_listener_); 86 // DCHECK(memory_pressure_listener_);
67 DCHECK(allocations_.Peek(allocation) == allocations_.end()); 87 DCHECK(allocations_.Peek(allocation) == allocations_.end());
68 allocations_.Put(allocation, AllocationInfo(bytes)); 88 allocations_.Put(allocation, AllocationInfo(bytes));
69 } 89 }
70 90
71 void DiscardableMemoryManager::Unregister(Allocation* allocation) { 91 void DiscardableMemoryManager::Unregister(Allocation* allocation) {
72 AutoLock lock(lock_); 92 AutoLock lock(lock_);
73 AllocationMap::iterator it = allocations_.Peek(allocation); 93 AllocationMap::iterator it = allocations_.Peek(allocation);
74 DCHECK(it != allocations_.end()); 94 DCHECK(it != allocations_.end());
75 const AllocationInfo& info = it->second; 95 const AllocationInfo& info = it->second;
76 96
77 if (info.purgable) { 97 if (info.purgable) {
78 size_t bytes_purgable = info.bytes; 98 size_t bytes_purgable = info.bytes;
79 DCHECK_LE(bytes_purgable, bytes_allocated_); 99 DCHECK_LE(bytes_purgable, bytes_allocated_);
80 bytes_allocated_ -= bytes_purgable; 100 bytes_allocated_ -= bytes_purgable;
81 BytesAllocatedChanged(); 101 BytesAllocatedChanged(bytes_allocated_);
82 } 102 }
83 allocations_.Erase(it); 103 allocations_.Erase(it);
84 } 104 }
85 105
86 bool DiscardableMemoryManager::AcquireLock(Allocation* allocation, 106 bool DiscardableMemoryManager::AcquireLock(Allocation* allocation,
87 bool* purged) { 107 bool* purged) {
88 AutoLock lock(lock_); 108 AutoLock lock(lock_);
89 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that 109 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
90 // cache. 110 // cache.
91 AllocationMap::iterator it = allocations_.Get(allocation); 111 AllocationMap::iterator it = allocations_.Get(allocation);
92 DCHECK(it != allocations_.end()); 112 DCHECK(it != allocations_.end());
93 AllocationInfo* info = &it->second; 113 AllocationInfo* info = &it->second;
94 114
95 if (!info->bytes) 115 if (!info->bytes)
96 return false; 116 return false;
97 117
118 TimeTicks now = Now();
98 size_t bytes_required = info->purgable ? 0u : info->bytes; 119 size_t bytes_required = info->purgable ? 0u : info->bytes;
99 120
100 if (memory_limit_) { 121 if (memory_limit_) {
101 size_t limit = 0; 122 size_t limit = 0;
102 if (bytes_required < memory_limit_) 123 if (bytes_required < memory_limit_)
103 limit = memory_limit_ - bytes_required; 124 limit = memory_limit_ - bytes_required;
104 125
105 PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit); 126 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(now,
127 limit);
106 } 128 }
107 129
108 // Check for overflow. 130 // Check for overflow.
109 if (std::numeric_limits<size_t>::max() - bytes_required < bytes_allocated_) 131 if (std::numeric_limits<size_t>::max() - bytes_required < bytes_allocated_)
110 return false; 132 return false;
111 133
112 *purged = !allocation->AllocateAndAcquireLock(); 134 *purged = !allocation->AllocateAndAcquireLock();
113 info->purgable = false; 135 info->purgable = false;
136 info->last_usage = now;
114 if (bytes_required) { 137 if (bytes_required) {
115 bytes_allocated_ += bytes_required; 138 bytes_allocated_ += bytes_required;
116 BytesAllocatedChanged(); 139 BytesAllocatedChanged(bytes_allocated_);
117 } 140 }
118 return true; 141 return true;
119 } 142 }
120 143
121 void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) { 144 void DiscardableMemoryManager::ReleaseLock(Allocation* allocation) {
122 AutoLock lock(lock_); 145 AutoLock lock(lock_);
123 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that 146 // Note: |allocations_| is an MRU cache, and use of |Get| here updates that
124 // cache. 147 // cache.
125 AllocationMap::iterator it = allocations_.Get(allocation); 148 AllocationMap::iterator it = allocations_.Get(allocation);
126 DCHECK(it != allocations_.end()); 149 DCHECK(it != allocations_.end());
127 AllocationInfo* info = &it->second; 150 AllocationInfo* info = &it->second;
128 151
152 TimeTicks now = Now();
129 allocation->ReleaseLock(); 153 allocation->ReleaseLock();
130 info->purgable = true; 154 info->purgable = true;
131 EnforcePolicyWithLockAcquired(); 155 info->last_usage = now;
156
157 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
158 now, memory_limit_);
132 } 159 }
133 160
134 void DiscardableMemoryManager::PurgeAll() { 161 void DiscardableMemoryManager::PurgeAll() {
135 AutoLock lock(lock_); 162 AutoLock lock(lock_);
136 PurgeLRUWithLockAcquiredUntilUsageIsWithin(0); 163 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(), 0);
137 } 164 }
138 165
139 bool DiscardableMemoryManager::IsRegisteredForTest( 166 bool DiscardableMemoryManager::IsRegisteredForTest(
140 Allocation* allocation) const { 167 Allocation* allocation) const {
141 AutoLock lock(lock_); 168 AutoLock lock(lock_);
142 AllocationMap::const_iterator it = allocations_.Peek(allocation); 169 AllocationMap::const_iterator it = allocations_.Peek(allocation);
143 return it != allocations_.end(); 170 return it != allocations_.end();
144 } 171 }
145 172
146 bool DiscardableMemoryManager::CanBePurgedForTest( 173 bool DiscardableMemoryManager::CanBePurgedForTest(
147 Allocation* allocation) const { 174 Allocation* allocation) const {
148 AutoLock lock(lock_); 175 AutoLock lock(lock_);
149 AllocationMap::const_iterator it = allocations_.Peek(allocation); 176 AllocationMap::const_iterator it = allocations_.Peek(allocation);
150 return it != allocations_.end() && it->second.purgable; 177 return it != allocations_.end() && it->second.purgable;
151 } 178 }
152 179
153 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const { 180 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
154 AutoLock lock(lock_); 181 AutoLock lock(lock_);
155 return bytes_allocated_; 182 return bytes_allocated_;
156 } 183 }
157 184
185 TimeTicks DiscardableMemoryManager::Now() const {
186 return TimeTicks::Now();
187 }
188
158 void DiscardableMemoryManager::OnMemoryPressure( 189 void DiscardableMemoryManager::OnMemoryPressure(
159 MemoryPressureListener::MemoryPressureLevel pressure_level) { 190 MemoryPressureListener::MemoryPressureLevel pressure_level) {
160 switch (pressure_level) { 191 switch (pressure_level) {
161 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE: 192 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
162 Purge(); 193 PurgeUntilWithinBytesToKeepUnderModeratePressure();
163 return; 194 return;
164 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL: 195 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
165 PurgeAll(); 196 PurgeAll();
166 return; 197 return;
167 } 198 }
168 199
169 NOTREACHED(); 200 NOTREACHED();
170 } 201 }
171 202
172 void DiscardableMemoryManager::Purge() { 203 void
204 DiscardableMemoryManager::PurgeUntilWithinBytesToKeepUnderModeratePressure() {
173 AutoLock lock(lock_); 205 AutoLock lock(lock_);
174 206
175 PurgeLRUWithLockAcquiredUntilUsageIsWithin( 207 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
176 bytes_to_keep_under_moderate_pressure_); 208 Now(), bytes_to_keep_under_moderate_pressure_);
177 } 209 }
178 210
179 void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin( 211 bool DiscardableMemoryManager::
180 size_t limit) { 212 PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
181 TRACE_EVENT1( 213 AutoLock lock(lock_);
182 "base",
183 "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
184 "limit",
185 limit);
186 214
215 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
216 Now() - hard_memory_limit_expiration_time_, soft_memory_limit_);
217
218 return bytes_allocated_ <= soft_memory_limit_;
219 }
220
221 void DiscardableMemoryManager::
222 PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
223 TimeTicks timestamp,
224 size_t limit) {
187 lock_.AssertAcquired(); 225 lock_.AssertAcquired();
188 226
189 size_t bytes_allocated_before_purging = bytes_allocated_; 227 size_t bytes_allocated_before_purging = bytes_allocated_;
190 for (AllocationMap::reverse_iterator it = allocations_.rbegin(); 228 for (AllocationMap::reverse_iterator it = allocations_.rbegin();
191 it != allocations_.rend(); 229 it != allocations_.rend();
192 ++it) { 230 ++it) {
193 Allocation* allocation = it->first; 231 Allocation* allocation = it->first;
194 AllocationInfo* info = &it->second; 232 AllocationInfo* info = &it->second;
195 233
196 if (bytes_allocated_ <= limit) 234 if (bytes_allocated_ <= limit)
197 break; 235 break;
198 if (!info->purgable) 236
237 bool purgable = info->purgable && info->last_usage <= timestamp;
238 if (!purgable)
199 continue; 239 continue;
200 240
201 size_t bytes_purgable = info->bytes; 241 size_t bytes_purgable = info->bytes;
202 DCHECK_LE(bytes_purgable, bytes_allocated_); 242 DCHECK_LE(bytes_purgable, bytes_allocated_);
203 bytes_allocated_ -= bytes_purgable; 243 bytes_allocated_ -= bytes_purgable;
204 info->purgable = false; 244 info->purgable = false;
205 allocation->Purge(); 245 allocation->Purge();
206 } 246 }
207 247
208 if (bytes_allocated_ != bytes_allocated_before_purging) 248 if (bytes_allocated_ != bytes_allocated_before_purging)
209 BytesAllocatedChanged(); 249 BytesAllocatedChanged(bytes_allocated_);
210 } 250 }
211 251
212 void DiscardableMemoryManager::EnforcePolicyWithLockAcquired() { 252 void DiscardableMemoryManager::BytesAllocatedChanged(
213 PurgeLRUWithLockAcquiredUntilUsageIsWithin(memory_limit_); 253 size_t new_bytes_allocated) const {
214 } 254 TRACE_COUNTER_ID1(
215 255 "base", "DiscardableMemoryUsage", this, new_bytes_allocated);
216 void DiscardableMemoryManager::BytesAllocatedChanged() const {
217 TRACE_COUNTER_ID1("base", "DiscardableMemoryUsage", this, bytes_allocated_);
218 256
219 static const char kDiscardableMemoryUsageKey[] = "dm-usage"; 257 static const char kDiscardableMemoryUsageKey[] = "dm-usage";
220 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey, 258 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey,
221 Uint64ToString(bytes_allocated_)); 259 Uint64ToString(new_bytes_allocated));
222 } 260 }
223 261
224 } // namespace internal 262 } // namespace internal
225 } // namespace base 263 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698