OLD | NEW |
---|---|
(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/memory/discardable_memory.h" | |
11 #include "base/memory/singleton.h" | |
12 #include "base/synchronization/lock.h" | |
13 #include "base/sys_info.h" | |
14 | |
15 namespace base { | |
16 | |
17 namespace { | |
18 | |
19 // If this is given a valid value via SetInstanceForTest, this pointer will be | |
20 // returned by GetInstance rather than the usual singleton. | |
21 static base::DiscardableMemoryProvider* s_provider_for_test = NULL; | |
22 | |
23 // This is admittedly pretty magical. It's approximately enough memory for two | |
24 // 2560x1600 images. | |
25 static const size_t kDefaultDiscardableMemoryLimit = 32 * 1024 * 1024; | |
26 static const size_t kDefaultBytesToReclaimUnderModeratePressure = | |
27 kDefaultDiscardableMemoryLimit / 2; | |
28 | |
29 } // namespace | |
30 | |
31 DiscardableMemoryProvider::DiscardableMemoryProvider() | |
32 : allocations_(AllocationMap::NO_AUTO_EVICT), | |
33 bytes_allocated_(0), | |
34 discardable_memory_limit_(kDefaultDiscardableMemoryLimit), | |
35 bytes_to_reclaim_under_moderate_pressure_( | |
36 kDefaultBytesToReclaimUnderModeratePressure), | |
37 memory_pressure_listener_(new MemoryPressureListener( | |
38 base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure))) { | |
39 } | |
40 | |
41 DiscardableMemoryProvider::~DiscardableMemoryProvider() { | |
Avi (use Gerrit)
2013/06/20 20:47:41
What is the scenario in which this gets called? I'
| |
42 AutoLock lock(allocations_lock_); | |
43 AllocationMap::iterator it = allocations_.begin(); | |
44 for (; it != allocations_.end(); ++it) | |
45 if (it->first->memory_) | |
46 it->first->Deallocate(); | |
47 } | |
48 | |
49 // static | |
50 DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() { | |
51 if (s_provider_for_test) | |
52 return s_provider_for_test; | |
53 return Singleton<DiscardableMemoryProvider>::get(); | |
54 } | |
55 | |
56 // static | |
57 void DiscardableMemoryProvider::SetInstanceForTest( | |
58 DiscardableMemoryProvider* provider) { | |
59 s_provider_for_test = provider; | |
60 } | |
61 | |
62 // static | |
63 void DiscardableMemoryProvider::NotifyMemoryPressure( | |
64 MemoryPressureListener::MemoryPressureLevel pressureLevel) { | |
65 switch (pressureLevel) { | |
66 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE: | |
67 DiscardableMemoryProvider::GetInstance()->PurgeLRU(); | |
68 break; | |
69 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL: | |
70 DiscardableMemoryProvider::GetInstance()->PurgeAll(); | |
71 break; | |
72 default: | |
73 NOTREACHED(); | |
74 } | |
75 } | |
76 | |
77 void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) { | |
78 { | |
79 AutoLock lock(bytes_allocated_lock_); | |
80 discardable_memory_limit_ = bytes; | |
81 } | |
82 EnforcePolicy(); | |
83 } | |
84 | |
85 size_t DiscardableMemoryProvider::discardable_memory_limit() const { | |
86 AutoLock lock( | |
87 const_cast<DiscardableMemoryProvider*>(this)->bytes_allocated_lock_); | |
Avi (use Gerrit)
2013/06/20 20:47:41
Yikes. Do we want to make the lock mutable then?
| |
88 return discardable_memory_limit_; | |
89 } | |
90 | |
91 void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure( | |
92 size_t bytes) { | |
93 { | |
94 AutoLock lock(bytes_allocated_lock_); | |
95 bytes_to_reclaim_under_moderate_pressure_ = bytes; | |
96 } | |
97 EnforcePolicy(); | |
98 } | |
99 | |
100 size_t DiscardableMemoryProvider:: | |
101 bytes_to_reclaim_under_moderate_pressure() const { | |
102 AutoLock lock( | |
103 const_cast<DiscardableMemoryProvider*>(this)->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(bytes <= bytes_allocated_); | |
138 bytes_allocated_ -= bytes; | |
139 } | |
140 EnforcePolicy(); | |
141 } | |
142 | |
143 bool DiscardableMemoryProvider::DidAccess(DiscardableMemory* discardable) { | |
144 AutoLock lock(allocations_lock_); | |
145 AllocationMap::iterator it = allocations_.Get(discardable); | |
146 return it != allocations_.end(); | |
147 } | |
148 | |
149 void DiscardableMemoryProvider::PurgeAll() { | |
150 AutoLock lock(allocations_lock_); | |
151 AllocationMap::iterator it = allocations_.begin(); | |
152 for (; it != allocations_.end(); ++it) { | |
153 if (it->first->memory_ && !it->first->is_locked()) { | |
154 it->first->Deallocate(); | |
155 DCHECK(!it->first->memory_); | |
156 } | |
157 } | |
158 } | |
159 | |
160 void DiscardableMemoryProvider::PurgeLRU() { | |
161 size_t limit = 0; | |
162 { | |
163 AutoLock lock(bytes_allocated_lock_); | |
164 if (bytes_to_reclaim_under_moderate_pressure_ == 0) | |
165 return; | |
166 | |
167 if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_) | |
168 limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_; | |
169 } | |
170 | |
171 AutoLock lock(allocations_lock_); | |
172 AllocationMap::reverse_iterator it = allocations_.rbegin(); | |
173 for(; it != allocations_.rend(); ++it) { | |
174 if (!it->first->memory_ || it->first->is_locked()) | |
175 continue; | |
176 it->first->Deallocate(); | |
177 DCHECK(!it->first->memory_); | |
178 AutoLock bytes_lock(bytes_allocated_lock_); | |
179 if (bytes_allocated_ <= limit) | |
180 break; | |
181 } | |
182 } | |
183 | |
184 void DiscardableMemoryProvider::EnforcePolicy() { | |
185 bool exceeded_bound = false; | |
186 { | |
187 AutoLock lock(bytes_allocated_lock_); | |
188 if (discardable_memory_limit_ == 0) | |
189 return; | |
190 exceeded_bound = bytes_allocated_ > discardable_memory_limit_; | |
191 } | |
192 if (exceeded_bound) | |
193 PurgeLRU(); | |
194 } | |
195 | |
196 } // namespace base | |
OLD | NEW |