OLD | NEW |
---|---|
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_emulated.h" | 5 #include "base/memory/discardable_memory_emulated.h" |
6 | 6 |
7 #include "base/bind.h" | |
7 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
8 #include "base/memory/discardable_memory_manager.h" | 9 #include "base/memory/memory_pressure_listener.h" |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/threading/thread_checker.h" | |
9 | 12 |
10 namespace base { | 13 namespace base { |
11 | 14 |
12 namespace { | 15 namespace { |
13 | 16 |
14 base::LazyInstance<internal::DiscardableMemoryManager>::Leaky g_manager = | 17 class DiscardableMemoryAllocationImpl |
willchan no longer on Chromium
2014/04/01 01:11:08
Maybe we should name this DiscardableMemoryHeapAll
reveman
2014/04/03 17:02:12
I added a comment here to emphasize the use of hea
willchan no longer on Chromium
2014/04/15 20:51:31
I will defer to you here. Please take my comment a
| |
18 : public internal::DiscardableMemoryAllocation { | |
19 public: | |
20 explicit DiscardableMemoryAllocationImpl(size_t bytes) | |
21 : memory_(new uint8[bytes]) {} | |
22 | |
23 // Overridden from internal::DiscardableMemoryAllocation: | |
24 virtual bool Lock() OVERRIDE { return true; } | |
25 virtual void Unlock() OVERRIDE {} | |
26 virtual void* Memory() OVERRIDE { return memory_.get(); } | |
27 | |
28 private: | |
29 scoped_ptr<uint8[]> memory_; | |
30 }; | |
31 | |
32 // This is admittedly pretty magical. It's approximately enough memory for four | |
33 // 2560x1600 images. | |
34 const size_t kDefaultDiscardableMemoryLimit = 64 * 1024 * 1024; | |
35 | |
36 // Under moderate memory pressure, we will purge until usage is within this | |
37 // limit. | |
38 const size_t kBytesToKeepUnderModeratePressure = | |
39 kDefaultDiscardableMemoryLimit / 4; | |
40 | |
41 class DiscardableMemoryManagerImpl | |
42 : public internal::DiscardableMemoryManager, | |
43 public internal::DiscardableMemoryAllocation::Factory { | |
44 public: | |
45 DiscardableMemoryManagerImpl() | |
46 : internal::DiscardableMemoryManager(this, | |
Philippe
2014/03/20 18:08:31
I think this part is slightly hairy :) Correct me
reveman
2014/03/20 19:08:22
Correct.
Philippe
2014/03/21 09:13:09
I think we will have to initialize the factory bef
Philippe
2014/03/21 09:49:19
I think this should be a reasonable compromise tha
reveman
2014/03/21 12:32:16
Why not?
reveman
2014/03/21 12:32:16
I don't like that either. Awkward for the manager
Philippe
2014/03/21 12:40:50
Because this would be a direct violation of the Li
reveman
2014/03/22 16:49:34
Correct, DiscardableMemoryManagerImpl is not a Fac
Philippe
2014/03/24 09:35:31
Just to be clear and so that the information is pr
willchan no longer on Chromium
2014/04/01 01:11:08
I am not fully up to date with Philippe's proposal
reveman
2014/04/03 17:02:12
Do we really need to avoid all kinds of concrete c
Philippe
2014/04/14 15:35:47
I agree, let's move this forward :) I think I have
willchan no longer on Chromium
2014/04/15 20:51:31
It's not strictly disallowed, but it's strongly di
| |
47 kDefaultDiscardableMemoryLimit) {} | |
48 | |
49 // Overridden from internal::DiscardableMemoryAllocation::Factory: | |
50 virtual scoped_ptr<internal::DiscardableMemoryAllocation> | |
51 CreateLockedAllocation(size_t bytes) OVERRIDE { | |
52 return make_scoped_ptr<internal::DiscardableMemoryAllocation>( | |
53 new DiscardableMemoryAllocationImpl(bytes)); | |
54 } | |
55 | |
56 void RegisterMemoryPressureListener() { | |
57 DCHECK(thread_checker_.CalledOnValidThread()); | |
58 DCHECK(base::MessageLoop::current()); | |
59 DCHECK(!memory_pressure_listener_); | |
60 memory_pressure_listener_.reset(new MemoryPressureListener(base::Bind( | |
61 &DiscardableMemoryManagerImpl::OnMemoryPressure, Unretained(this)))); | |
62 } | |
63 | |
64 void UnregisterMemoryPressureListener() { | |
65 DCHECK(thread_checker_.CalledOnValidThread()); | |
66 DCHECK(memory_pressure_listener_); | |
67 memory_pressure_listener_.reset(); | |
68 } | |
69 | |
70 // This can be called as a hint that the system is under memory pressure. | |
71 void OnMemoryPressure( | |
72 MemoryPressureListener::MemoryPressureLevel pressure_level) { | |
73 switch (pressure_level) { | |
74 case MemoryPressureListener::MEMORY_PRESSURE_MODERATE: | |
75 PurgeUntilUsageIsWithin(kBytesToKeepUnderModeratePressure); | |
76 return; | |
77 case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL: | |
78 PurgeUntilUsageIsWithin(0u); | |
79 return; | |
80 } | |
81 | |
82 NOTREACHED(); | |
83 } | |
84 | |
85 private: | |
86 // Allows us to be respond when the system reports that it is under memory | |
87 // pressure. | |
88 scoped_ptr<MemoryPressureListener> memory_pressure_listener_; | |
89 | |
90 base::ThreadChecker thread_checker_; | |
91 }; | |
92 base::LazyInstance<DiscardableMemoryManagerImpl>::Leaky g_manager = | |
15 LAZY_INSTANCE_INITIALIZER; | 93 LAZY_INSTANCE_INITIALIZER; |
16 | 94 |
17 } // namespace | 95 } // namespace |
18 | 96 |
19 namespace internal { | 97 namespace internal { |
20 | 98 |
21 DiscardableMemoryEmulated::DiscardableMemoryEmulated(size_t size) | 99 DiscardableMemoryEmulated::DiscardableMemoryEmulated(size_t size) |
22 : is_locked_(false) { | 100 : allocation_id_(g_manager.Pointer()->Register(size)), memory_(NULL) {} |
23 g_manager.Pointer()->Register(this, size); | |
24 } | |
25 | 101 |
26 DiscardableMemoryEmulated::~DiscardableMemoryEmulated() { | 102 DiscardableMemoryEmulated::~DiscardableMemoryEmulated() { |
27 if (is_locked_) | 103 g_manager.Pointer()->Unregister(allocation_id_); |
28 Unlock(); | |
29 g_manager.Pointer()->Unregister(this); | |
30 } | 104 } |
31 | 105 |
32 // static | 106 // static |
33 void DiscardableMemoryEmulated::RegisterMemoryPressureListeners() { | 107 void DiscardableMemoryEmulated::RegisterMemoryPressureListeners() { |
34 g_manager.Pointer()->RegisterMemoryPressureListener(); | 108 g_manager.Pointer()->RegisterMemoryPressureListener(); |
35 } | 109 } |
36 | 110 |
37 // static | 111 // static |
38 void DiscardableMemoryEmulated::UnregisterMemoryPressureListeners() { | 112 void DiscardableMemoryEmulated::UnregisterMemoryPressureListeners() { |
39 g_manager.Pointer()->UnregisterMemoryPressureListener(); | 113 g_manager.Pointer()->UnregisterMemoryPressureListener(); |
40 } | 114 } |
41 | 115 |
42 // static | 116 // static |
43 void DiscardableMemoryEmulated::PurgeForTesting() { | 117 void DiscardableMemoryEmulated::PurgeForTesting() { |
44 g_manager.Pointer()->PurgeAll(); | 118 g_manager.Pointer()->PurgeUntilUsageIsWithin(0u); |
45 } | 119 } |
46 | 120 |
47 bool DiscardableMemoryEmulated::Initialize() { | 121 bool DiscardableMemoryEmulated::Initialize() { |
48 return Lock() == DISCARDABLE_MEMORY_LOCK_STATUS_PURGED; | 122 return Lock() == DISCARDABLE_MEMORY_LOCK_STATUS_PURGED; |
49 } | 123 } |
50 | 124 |
51 DiscardableMemoryLockStatus DiscardableMemoryEmulated::Lock() { | 125 DiscardableMemoryLockStatus DiscardableMemoryEmulated::Lock() { |
52 DCHECK(!is_locked_); | 126 DCHECK(!memory_); |
53 | 127 |
54 bool purged = false; | 128 bool purged = false; |
55 memory_ = g_manager.Pointer()->Acquire(this, &purged); | 129 memory_ = g_manager.Pointer()->Lock(allocation_id_, &purged); |
56 if (!memory_) | 130 if (!memory_) |
57 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | 131 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; |
58 | 132 |
59 is_locked_ = true; | |
60 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED | 133 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED |
61 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; | 134 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; |
62 } | 135 } |
63 | 136 |
64 void DiscardableMemoryEmulated::Unlock() { | 137 void DiscardableMemoryEmulated::Unlock() { |
65 DCHECK(is_locked_); | 138 DCHECK(memory_); |
66 g_manager.Pointer()->Release(this, memory_.Pass()); | 139 g_manager.Pointer()->Unlock(allocation_id_); |
67 is_locked_ = false; | 140 memory_ = NULL; |
68 } | 141 } |
69 | 142 |
70 void* DiscardableMemoryEmulated::Memory() const { | 143 void* DiscardableMemoryEmulated::Memory() const { |
71 DCHECK(memory_); | 144 DCHECK(memory_); |
72 return memory_.get(); | 145 return memory_; |
73 } | 146 } |
74 | 147 |
75 } // namespace internal | 148 } // namespace internal |
76 } // namespace base | 149 } // namespace base |
OLD | NEW |