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

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

Issue 204733003: base: Refactor DiscardableMemoryManager for use with different type of allocations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add missing unlock call and remove unnecessary unlock call Created 6 years, 9 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 2013 The Chromium Authors. All rights reserved. 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 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"
8 #include "base/containers/hash_tables.h" 7 #include "base/containers/hash_tables.h"
9 #include "base/containers/mru_cache.h" 8 #include "base/containers/mru_cache.h"
10 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
11 #include "base/synchronization/lock.h" 10 #include "base/synchronization/lock.h"
12 #include "base/sys_info.h"
13 11
14 namespace base { 12 namespace base {
15 namespace internal { 13 namespace internal {
16 14
17 namespace { 15 DiscardableMemoryManager::AllocationInfo::AllocationInfo(size_t bytes)
16 : bytes(bytes), locked(false) {}
18 17
19 // This is admittedly pretty magical. It's approximately enough memory for four 18 DiscardableMemoryManager::AllocationInfo::~AllocationInfo() {}
20 // 2560x1600 images.
21 static const size_t kDefaultDiscardableMemoryLimit = 64 * 1024 * 1024;
22 static const size_t kDefaultBytesToKeepUnderModeratePressure =
23 kDefaultDiscardableMemoryLimit / 4;
24 19
25 } // namespace 20 DiscardableMemoryManager::DiscardableMemoryManager(
26 21 DiscardableMemoryAllocation::Factory* allocation_factory,
27 DiscardableMemoryManager::DiscardableMemoryManager() 22 size_t discardable_memory_limit)
28 : allocations_(AllocationMap::NO_AUTO_EVICT), 23 : allocation_factory_(allocation_factory),
24 next_allocation_id_(0),
25 allocations_(AllocationMap::NO_AUTO_EVICT),
29 bytes_allocated_(0), 26 bytes_allocated_(0),
30 discardable_memory_limit_(kDefaultDiscardableMemoryLimit), 27 discardable_memory_limit_(discardable_memory_limit) {}
31 bytes_to_keep_under_moderate_pressure_(
32 kDefaultBytesToKeepUnderModeratePressure) {
33 }
34 28
35 DiscardableMemoryManager::~DiscardableMemoryManager() { 29 DiscardableMemoryManager::~DiscardableMemoryManager() {
36 DCHECK(allocations_.empty()); 30 DCHECK(allocations_.empty());
37 DCHECK_EQ(0u, bytes_allocated_); 31 DCHECK_EQ(0u, bytes_allocated_);
38 } 32 }
39 33
40 void DiscardableMemoryManager::RegisterMemoryPressureListener() {
41 AutoLock lock(lock_);
42 DCHECK(base::MessageLoop::current());
43 DCHECK(!memory_pressure_listener_);
44 memory_pressure_listener_.reset(
45 new MemoryPressureListener(
46 base::Bind(&DiscardableMemoryManager::OnMemoryPressure,
47 Unretained(this))));
48 }
49
50 void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
51 AutoLock lock(lock_);
52 DCHECK(memory_pressure_listener_);
53 memory_pressure_listener_.reset();
54 }
55
56 void DiscardableMemoryManager::SetDiscardableMemoryLimit(size_t bytes) { 34 void DiscardableMemoryManager::SetDiscardableMemoryLimit(size_t bytes) {
57 AutoLock lock(lock_); 35 AutoLock lock(lock_);
58 discardable_memory_limit_ = bytes; 36 discardable_memory_limit_ = bytes;
59 EnforcePolicyWithLockAcquired(); 37 EnforcePolicyWithLockAcquired();
60 } 38 }
61 39
62 void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure( 40 DiscardableMemoryManager::AllocationId DiscardableMemoryManager::Register(
63 size_t bytes) { 41 size_t bytes) {
64 AutoLock lock(lock_); 42 AutoLock lock(lock_);
65 bytes_to_keep_under_moderate_pressure_ = bytes; 43 AllocationId allocation_id = next_allocation_id_++;
66 } 44 if (next_allocation_id_ == INT_MAX)
67 45 next_allocation_id_ = 1;
68 void DiscardableMemoryManager::Register(
69 const DiscardableMemory* discardable, size_t bytes) {
70 AutoLock lock(lock_);
71 // A registered memory listener is currently required. This DCHECK can be 46 // A registered memory listener is currently required. This DCHECK can be
72 // moved or removed if we decide that it's useful to relax this condition. 47 // moved or removed if we decide that it's useful to relax this condition.
73 // TODO(reveman): Enable this DCHECK when skia and blink are able to 48 // TODO(reveman): Enable this DCHECK when skia and blink are able to
74 // register memory pressure listeners. crbug.com/333907 49 // register memory pressure listeners. crbug.com/333907
75 // DCHECK(memory_pressure_listener_); 50 // DCHECK(memory_pressure_listener_);
76 DCHECK(allocations_.Peek(discardable) == allocations_.end()); 51 DCHECK(allocations_.Peek(allocation_id) == allocations_.end());
77 allocations_.Put(discardable, Allocation(bytes)); 52 allocations_.Put(allocation_id, AllocationInfo(bytes));
53 return allocation_id;
78 } 54 }
79 55
80 void DiscardableMemoryManager::Unregister( 56 void DiscardableMemoryManager::Unregister(AllocationId allocation_id) {
81 const DiscardableMemory* discardable) {
82 AutoLock lock(lock_); 57 AutoLock lock(lock_);
83 AllocationMap::iterator it = allocations_.Peek(discardable); 58 AllocationMap::iterator it = allocations_.Peek(allocation_id);
84 if (it == allocations_.end()) 59 if (it == allocations_.end())
85 return; 60 return;
86 61
87 if (it->second.memory) { 62 if (it->second.allocation.get()) {
88 size_t bytes = it->second.bytes; 63 size_t bytes = it->second.bytes;
89 DCHECK_LE(bytes, bytes_allocated_); 64 DCHECK_LE(bytes, bytes_allocated_);
90 bytes_allocated_ -= bytes; 65 bytes_allocated_ -= bytes;
91 free(it->second.memory); 66 it->second.allocation.reset();
92 } 67 }
93 allocations_.Erase(it); 68 allocations_.Erase(it);
94 } 69 }
95 70
96 scoped_ptr<uint8, FreeDeleter> DiscardableMemoryManager::Acquire( 71 void* DiscardableMemoryManager::Lock(AllocationId allocation_id, bool* purged) {
97 const DiscardableMemory* discardable,
98 bool* purged) {
99 AutoLock lock(lock_); 72 AutoLock lock(lock_);
100 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that 73 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
101 // cache. 74 // cache.
102 AllocationMap::iterator it = allocations_.Get(discardable); 75 AllocationMap::iterator it = allocations_.Get(allocation_id);
103 CHECK(it != allocations_.end()); 76 CHECK(it != allocations_.end());
104 77
105 if (it->second.memory) { 78 if (it->second.allocation.get()) {
106 scoped_ptr<uint8, FreeDeleter> memory(it->second.memory); 79 DiscardableMemoryAllocation* allocation = it->second.allocation.get();
107 it->second.memory = NULL; 80
108 *purged = false; 81 DCHECK(!it->second.locked);
109 return memory.Pass(); 82 it->second.locked = true;
83 *purged = !allocation->Lock();
84 return allocation->Memory();
110 } 85 }
111 86
112 size_t bytes = it->second.bytes; 87 size_t bytes = it->second.bytes;
113 if (!bytes) 88 if (!bytes)
114 return scoped_ptr<uint8, FreeDeleter>(); 89 return NULL;
115 90
116 if (discardable_memory_limit_) { 91 if (discardable_memory_limit_) {
117 size_t limit = 0; 92 size_t limit = 0;
118 if (bytes < discardable_memory_limit_) 93 if (bytes < discardable_memory_limit_)
119 limit = discardable_memory_limit_ - bytes; 94 limit = discardable_memory_limit_ - bytes;
120 95
121 PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit); 96 PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
122 } 97 }
123 98
124 // Check for overflow. 99 // Check for overflow.
125 if (std::numeric_limits<size_t>::max() - bytes < bytes_allocated_) 100 if (std::numeric_limits<size_t>::max() - bytes < bytes_allocated_)
126 return scoped_ptr<uint8, FreeDeleter>(); 101 return NULL;
127 102
128 scoped_ptr<uint8, FreeDeleter> memory(static_cast<uint8*>(malloc(bytes))); 103 linked_ptr<DiscardableMemoryAllocation> allocation(
129 if (!memory) 104 allocation_factory_->CreateLockedAllocation(bytes).release());
130 return scoped_ptr<uint8, FreeDeleter>(); 105 if (!allocation.get())
106 return NULL;
131 107
108 it->second.allocation = allocation;
109 it->second.locked = true;
132 bytes_allocated_ += bytes; 110 bytes_allocated_ += bytes;
133 *purged = true; 111 *purged = true;
134 return memory.Pass(); 112 return allocation->Memory();
135 } 113 }
136 114
137 void DiscardableMemoryManager::Release( 115 void DiscardableMemoryManager::Unlock(AllocationId allocation_id) {
138 const DiscardableMemory* discardable,
139 scoped_ptr<uint8, FreeDeleter> memory) {
140 AutoLock lock(lock_); 116 AutoLock lock(lock_);
141 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that 117 // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
142 // cache. 118 // cache.
143 AllocationMap::iterator it = allocations_.Get(discardable); 119 AllocationMap::iterator it = allocations_.Get(allocation_id);
144 CHECK(it != allocations_.end()); 120 CHECK(it != allocations_.end());
145 121
146 DCHECK(!it->second.memory); 122 DCHECK(it->second.allocation.get());
147 it->second.memory = memory.release(); 123 DCHECK(it->second.locked);
148 124 it->second.locked = false;
125 it->second.allocation->Unlock();
149 EnforcePolicyWithLockAcquired(); 126 EnforcePolicyWithLockAcquired();
150 } 127 }
151 128
152 void DiscardableMemoryManager::PurgeAll() { 129 void DiscardableMemoryManager::PurgeUntilUsageIsWithin(size_t limit) {
153 AutoLock lock(lock_); 130 AutoLock lock(lock_);
154 PurgeLRUWithLockAcquiredUntilUsageIsWithin(0); 131 PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
155 } 132 }
156 133
157 bool DiscardableMemoryManager::IsRegisteredForTest( 134 bool DiscardableMemoryManager::IsRegisteredForTest(
158 const DiscardableMemory* discardable) const { 135 AllocationId allocation_id) const {
159 AutoLock lock(lock_); 136 AutoLock lock(lock_);
160 AllocationMap::const_iterator it = allocations_.Peek(discardable); 137 AllocationMap::const_iterator it = allocations_.Peek(allocation_id);
161 return it != allocations_.end(); 138 return it != allocations_.end();
162 } 139 }
163 140
164 bool DiscardableMemoryManager::CanBePurgedForTest( 141 bool DiscardableMemoryManager::CanBePurgedForTest(
165 const DiscardableMemory* discardable) const { 142 AllocationId allocation_id) const {
166 AutoLock lock(lock_); 143 AutoLock lock(lock_);
167 AllocationMap::const_iterator it = allocations_.Peek(discardable); 144 AllocationMap::const_iterator it = allocations_.Peek(allocation_id);
168 return it != allocations_.end() && it->second.memory; 145 return it != allocations_.end() && !it->second.locked;
169 } 146 }
170 147
171 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const { 148 size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
172 AutoLock lock(lock_); 149 AutoLock lock(lock_);
173 return bytes_allocated_; 150 return bytes_allocated_;
174 } 151 }
175 152
176 void DiscardableMemoryManager::OnMemoryPressure(
177 MemoryPressureListener::MemoryPressureLevel pressure_level) {
178 switch (pressure_level) {
179 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
180 Purge();
181 return;
182 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
183 PurgeAll();
184 return;
185 }
186
187 NOTREACHED();
188 }
189
190 void DiscardableMemoryManager::Purge() {
191 AutoLock lock(lock_);
192
193 PurgeLRUWithLockAcquiredUntilUsageIsWithin(
194 bytes_to_keep_under_moderate_pressure_);
195 }
196
197 void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin( 153 void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
198 size_t limit) { 154 size_t limit) {
199 TRACE_EVENT1( 155 TRACE_EVENT1(
200 "base", 156 "base",
201 "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin", 157 "DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin",
202 "limit", limit); 158 "limit", limit);
203 159
204 lock_.AssertAcquired(); 160 lock_.AssertAcquired();
205 161
206 for (AllocationMap::reverse_iterator it = allocations_.rbegin(); 162 for (AllocationMap::reverse_iterator it = allocations_.rbegin();
207 it != allocations_.rend(); 163 it != allocations_.rend();
208 ++it) { 164 ++it) {
209 if (bytes_allocated_ <= limit) 165 if (bytes_allocated_ <= limit)
210 break; 166 break;
211 if (!it->second.memory) 167 if (!it->second.allocation.get())
168 continue;
169 if (it->second.locked)
212 continue; 170 continue;
213 171
214 size_t bytes = it->second.bytes; 172 size_t bytes = it->second.bytes;
215 DCHECK_LE(bytes, bytes_allocated_); 173 DCHECK_LE(bytes, bytes_allocated_);
216 bytes_allocated_ -= bytes; 174 bytes_allocated_ -= bytes;
217 free(it->second.memory); 175 it->second.allocation.reset();
218 it->second.memory = NULL;
219 } 176 }
220 } 177 }
221 178
222 void DiscardableMemoryManager::EnforcePolicyWithLockAcquired() { 179 void DiscardableMemoryManager::EnforcePolicyWithLockAcquired() {
223 PurgeLRUWithLockAcquiredUntilUsageIsWithin(discardable_memory_limit_); 180 PurgeLRUWithLockAcquiredUntilUsageIsWithin(discardable_memory_limit_);
224 } 181 }
225 182
226 } // namespace internal 183 } // namespace internal
227 } // namespace base 184 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698