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

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

Issue 17106004: Add discardable memory emulation for non-android/mac platforms (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address review feedback Created 7 years, 2 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
(Empty)
1 // Copyright 2013 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 "base/memory/discardable_memory_provider.h"
6
7 #include "base/bind.h"
8 #include "base/containers/hash_tables.h"
9 #include "base/containers/mru_cache.h"
10 #include "base/debug/trace_event.h"
11 #include "base/memory/discardable_memory.h"
12 #include "base/synchronization/lock.h"
13 #include "base/sys_info.h"
14
15 namespace base {
16 namespace internal {
17
18 namespace {
19
20 // If this is given a valid value via SetInstanceForTest, this pointer will be
21 // returned by GetInstance rather than the usual singleton.
22 static DiscardableMemoryProvider* s_provider_for_test = NULL;
23
24 // This is admittedly pretty magical. It's approximately enough memory for two
25 // 2560x1600 images.
26 static const size_t kDefaultDiscardableMemoryLimit = 32 * 1024 * 1024;
27 static const size_t kDefaultBytesToReclaimUnderModeratePressure =
28 kDefaultDiscardableMemoryLimit / 2;
29
30 } // namespace
31
32 DiscardableMemoryProvider::DiscardableMemoryProvider()
33 : allocations_(AllocationMap::NO_AUTO_EVICT),
34 bytes_allocated_(0),
35 discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
36 bytes_to_reclaim_under_moderate_pressure_(
37 kDefaultBytesToReclaimUnderModeratePressure),
38 memory_pressure_listener_(
39 base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure)) {
40 }
41
42 DiscardableMemoryProvider::~DiscardableMemoryProvider() {
43 DCHECK_EQ(0u, allocations_.size());
willchan no longer on Chromium 2013/10/21 18:30:27 DCHECK(allocations_.empty()); size() is linear in
reveman 2013/10/22 00:11:42 Done.
44 DCHECK_EQ(0u, bytes_allocated_);
45 }
46
47 // static
48 DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() {
49 if (s_provider_for_test)
50 return s_provider_for_test;
51 return Singleton<DiscardableMemoryProvider>::get();
52 }
53
54 // static
55 void DiscardableMemoryProvider::SetInstanceForTest(
56 DiscardableMemoryProvider* provider) {
57 s_provider_for_test = provider;
58 }
59
60 // static
61 void DiscardableMemoryProvider::NotifyMemoryPressure(
62 MemoryPressureListener::MemoryPressureLevel pressure_level) {
63 switch (pressure_level) {
64 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
65 DiscardableMemoryProvider::GetInstance()->Purge();
66 return;
67 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
68 DiscardableMemoryProvider::GetInstance()->PurgeAll();
69 return;
70 }
71
72 NOTREACHED();
73 }
74
75 void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) {
76 AutoLock lock(lock_);
77 discardable_memory_limit_ = bytes;
78 EnforcePolicy();
79 }
80
81 void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure(
82 size_t bytes) {
83 AutoLock lock(lock_);
84 bytes_to_reclaim_under_moderate_pressure_ = bytes;
85 EnforcePolicy();
86 }
87
88 void DiscardableMemoryProvider::Register(
89 const DiscardableMemory* discardable, size_t bytes) {
90 AutoLock lock(lock_);
91 DCHECK(allocations_.Peek(discardable) == allocations_.end());
92 allocations_.Put(discardable, Allocation(bytes));
93 }
94
95 void DiscardableMemoryProvider::Unregister(
96 const DiscardableMemory* discardable) {
97 AutoLock lock(lock_);
98 AllocationMap::iterator it = allocations_.Peek(discardable);
99 if (it == allocations_.end())
100 return;
101
102 if (it->second.memory) {
103 size_t bytes = it->second.bytes;
104 DCHECK_LE(bytes, bytes_allocated_);
105 bytes_allocated_ -= bytes;
106 free(it->second.memory);
107 }
108 allocations_.Erase(it);
109 }
110
111 scoped_ptr<uint8, FreeDeleter> DiscardableMemoryProvider::Acquire(
112 const DiscardableMemory* discardable,
113 bool* purged) {
114 AutoLock lock(lock_);
115 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
116 // cache.
117 AllocationMap::iterator it = allocations_.Get(discardable);
118 CHECK(it != allocations_.end());
119
120 if (it->second.memory) {
121 scoped_ptr<uint8, FreeDeleter> memory(it->second.memory);
122 it->second.memory = NULL;
123 *purged = false;
124 return memory.Pass();
125 }
126
127 size_t bytes = it->second.bytes;
128 if (!bytes)
129 return scoped_ptr<uint8, FreeDeleter>();
130
131 if (discardable_memory_limit_) {
132 if (bytes > discardable_memory_limit_)
willchan no longer on Chromium 2013/10/21 21:29:12 I'm confused. The comment for this variable says:
reveman 2013/10/22 00:11:42 Talked to vollick@ and I don't think we should hav
133 return scoped_ptr<uint8, FreeDeleter>();
134
135 size_t limit = discardable_memory_limit_ - bytes;
136 PurgeLRU(limit);
137
138 if (bytes_allocated_ > limit)
139 return scoped_ptr<uint8, FreeDeleter>();
140 }
141
142 bytes_allocated_ += bytes;
143 *purged = true;
144 return scoped_ptr<uint8, FreeDeleter>(static_cast<uint8*>(malloc(bytes)));
145 }
146
147 void DiscardableMemoryProvider::Release(
148 const DiscardableMemory* discardable,
149 scoped_ptr<uint8, FreeDeleter> memory) {
150 AutoLock lock(lock_);
151 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
152 // cache.
153 AllocationMap::iterator it = allocations_.Get(discardable);
154 CHECK(it != allocations_.end());
155
156 DCHECK(!it->second.memory);
157 it->second.memory = memory.release();
158
159 EnforcePolicy();
160 }
161
162 bool DiscardableMemoryProvider::IsRegisteredForTest(
willchan no longer on Chromium 2013/10/21 21:29:12 Please order functions in the .cc file to match th
reveman 2013/10/22 00:11:42 Done.
163 const DiscardableMemory* discardable) const {
164 AutoLock lock(lock_);
165 AllocationMap::const_iterator it = allocations_.Peek(discardable);
166 return it != allocations_.end();
167 }
168
169 bool DiscardableMemoryProvider::CanBePurgedForTest(
170 const DiscardableMemory* discardable) const {
171 AutoLock lock(lock_);
172 AllocationMap::const_iterator it = allocations_.Peek(discardable);
173 return it != allocations_.end() && it->second.memory;
174 }
175
176 size_t DiscardableMemoryProvider::GetBytesAllocatedForTest() const {
177 AutoLock lock(lock_);
178 return bytes_allocated_;
179 }
180
181 void DiscardableMemoryProvider::PurgeLRU(size_t limit) {
182 TRACE_EVENT1("base", "DiscardableMemoryProvider::PurgeLRU", "limit", limit);
183
184 lock_.AssertAcquired();
willchan no longer on Chromium 2013/10/21 21:29:12 Sometimes people use a naming convention to make i
reveman 2013/10/22 00:11:42 Added "WithLockAcquired" to the name of the functi
185
186 for (AllocationMap::reverse_iterator it = allocations_.rbegin();
187 it != allocations_.rend();
188 ++it) {
189 if (bytes_allocated_ <= limit)
190 break;
191 if (!it->second.memory)
192 continue;
193
194 size_t bytes = it->second.bytes;
195 DCHECK_LE(bytes, bytes_allocated_);
196 bytes_allocated_ -= bytes;
197 free(it->second.memory);
198 it->second.memory = NULL;
199 }
200 }
201
202 void DiscardableMemoryProvider::Purge() {
203 AutoLock lock(lock_);
204
205 if (bytes_to_reclaim_under_moderate_pressure_ == 0)
206 return;
207
208 size_t limit = 0;
209 if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
210 limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
211
212 PurgeLRU(limit);
213 }
214
215 void DiscardableMemoryProvider::PurgeAll() {
216 AutoLock lock(lock_);
217 PurgeLRU(0);
218 }
219
220 void DiscardableMemoryProvider::EnforcePolicy() {
221 lock_.AssertAcquired();
222
223 bool exceeded_bound = bytes_allocated_ > discardable_memory_limit_;
224 if (!exceeded_bound || !bytes_to_reclaim_under_moderate_pressure_)
225 return;
226
227 size_t limit = 0;
228 if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
229 limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
230
231 PurgeLRU(limit);
232 }
233
234 } // namespace internal
235 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698