Chromium Code Reviews| 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 |