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

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: Addressing review. Created 7 years, 3 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 enforcing_policy_(false),
39 memory_pressure_listener_(
40 base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure)) {
41 }
42
43 DiscardableMemoryProvider::~DiscardableMemoryProvider() {
44 AutoLock lock(allocations_lock_);
45 AllocationMap::iterator it = allocations_.begin();
46 for (; it != allocations_.end(); ++it)
willchan no longer on Chromium 2013/10/01 18:47:25 Mind putting braces around this? I know it works,
reveman 2013/10/09 22:40:24 Done.
47 if (it->first->memory_)
48 it->first->Deallocate();
49 }
50
51 // static
52 DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() {
53 if (s_provider_for_test)
54 return s_provider_for_test;
55 return Singleton<DiscardableMemoryProvider>::get();
56 }
57
58 // static
59 void DiscardableMemoryProvider::SetInstanceForTest(
60 DiscardableMemoryProvider* provider) {
61 s_provider_for_test = provider;
62 }
63
64 // static
65 void DiscardableMemoryProvider::NotifyMemoryPressure(
willchan no longer on Chromium 2013/10/01 18:47:25 OK, there's a bug here. NotifyMemoryPressure will
reveman 2013/10/09 22:40:24 This is supposed to be fixed in my latest patch. P
66 MemoryPressureListener::MemoryPressureLevel pressure_level) {
67 switch (pressure_level) {
68 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
69 DiscardableMemoryProvider::GetInstance()->PurgeLRU();
70 break;
71 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
72 DiscardableMemoryProvider::GetInstance()->PurgeAll();
73 break;
74 default:
75 NOTREACHED();
reveman 2013/10/09 22:40:24 Note: I removed the default case and moved the NOT
76 }
77 }
78
79 void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) {
80 {
81 AutoLock lock(bytes_allocated_lock_);
82 discardable_memory_limit_ = bytes;
83 }
84 EnforcePolicy();
85 }
86
87 size_t DiscardableMemoryProvider::discardable_memory_limit() const {
88 AutoLock lock(bytes_allocated_lock_);
89 return discardable_memory_limit_;
90 }
91
92 void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure(
93 size_t bytes) {
94 {
95 AutoLock lock(bytes_allocated_lock_);
96 bytes_to_reclaim_under_moderate_pressure_ = bytes;
97 }
98 EnforcePolicy();
99 }
100
101 size_t DiscardableMemoryProvider::
102 bytes_to_reclaim_under_moderate_pressure() const {
103 AutoLock lock(bytes_allocated_lock_);
104 return bytes_to_reclaim_under_moderate_pressure_;
105 }
106
107 void DiscardableMemoryProvider::Register(DiscardableMemory* discardable) {
108 DCHECK(allocations_.Peek(discardable) == allocations_.end());
109 {
110 AutoLock lock(allocations_lock_);
111 allocations_.Put(discardable, true);
112 }
113 EnforcePolicy();
114 }
115
116 void DiscardableMemoryProvider::Unregister(DiscardableMemory* discardable) {
117 {
118 AutoLock lock(allocations_lock_);
119 AllocationMap::iterator it = allocations_.Peek(discardable);
120 if (it != allocations_.end())
121 allocations_.Erase(it);
122 }
123 EnforcePolicy();
124 }
125
126 void DiscardableMemoryProvider::DidAllocate(size_t bytes) {
127 {
128 AutoLock lock(bytes_allocated_lock_);
129 bytes_allocated_ += bytes;
130 }
131 EnforcePolicy();
132 }
133
134 void DiscardableMemoryProvider::DidDeallocate(size_t bytes) {
135 {
136 AutoLock lock(bytes_allocated_lock_);
137 DCHECK_LE(bytes, bytes_allocated_);
138 bytes_allocated_ -= bytes;
139 }
140 EnforcePolicy();
141 }
142
143 bool DiscardableMemoryProvider::DidAccess(DiscardableMemory* discardable) {
144 AutoLock lock(allocations_lock_);
145 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
146 // cache.
147 AllocationMap::iterator it = allocations_.Get(discardable);
148 return it != allocations_.end();
149 }
150
151 void DiscardableMemoryProvider::PurgeAll() {
152 TRACE_EVENT0("base", "DiscardableMemoryProvider::PurgeAll");
153
154 AutoLock lock(allocations_lock_);
155 AllocationMap::iterator it = allocations_.begin();
156 for (; it != allocations_.end(); ++it) {
157 if (it->first->memory_ && !it->first->is_locked()) {
158 it->first->Deallocate();
159 DCHECK(!it->first->memory_);
160 }
161 }
162 }
163
164 void DiscardableMemoryProvider::PurgeLRU() {
165 size_t limit = 0;
166 {
167 AutoLock lock(bytes_allocated_lock_);
168 if (bytes_to_reclaim_under_moderate_pressure_ == 0)
169 return;
170
171 if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
172 limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
173 }
174
175 TRACE_EVENT0("base", "DiscardableMemoryProvider::PurgeLRU");
176 AutoLock lock(allocations_lock_);
177 AllocationMap::reverse_iterator it = allocations_.rbegin();
178 for(; it != allocations_.rend(); ++it) {
179 if (!it->first->memory_ || it->first->is_locked())
180 continue;
181 it->first->Deallocate();
182 DCHECK(!it->first->memory_);
183 AutoLock bytes_lock(bytes_allocated_lock_);
184 if (bytes_allocated_ <= limit)
185 break;
186 }
187 }
188
189 void DiscardableMemoryProvider::EnforcePolicy() {
190 {
191 AutoLock lock(bytes_allocated_lock_);
192 if (enforcing_policy_)
193 return;
194 }
195
196 bool exceeded_bound = false;
197 {
198 AutoLock lock(bytes_allocated_lock_);
199 enforcing_policy_ = true;
200 if (discardable_memory_limit_ == 0) {
201 enforcing_policy_ = false;
202 return;
203 }
204 exceeded_bound = bytes_allocated_ > discardable_memory_limit_;
205 }
206
207 if (exceeded_bound)
208 PurgeLRU();
209
210 {
211 AutoLock lock(bytes_allocated_lock_);
212 enforcing_policy_ = false;
213 }
214 }
215
216 } // namespace internal
217 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698