| Index: base/memory/discardable_memory_manager.cc
|
| diff --git a/base/memory/discardable_memory_manager.cc b/base/memory/discardable_memory_manager.cc
|
| index fc263521015340b4687cfddc12e040f1746faf7f..ea5e45f56a55b543c71521fe305cdfd9948c2350 100644
|
| --- a/base/memory/discardable_memory_manager.cc
|
| +++ b/base/memory/discardable_memory_manager.cc
|
| @@ -4,114 +4,89 @@
|
|
|
| #include "base/memory/discardable_memory_manager.h"
|
|
|
| -#include "base/bind.h"
|
| #include "base/containers/hash_tables.h"
|
| #include "base/containers/mru_cache.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/synchronization/lock.h"
|
| -#include "base/sys_info.h"
|
|
|
| namespace base {
|
| namespace internal {
|
|
|
| -namespace {
|
| +DiscardableMemoryManager::AllocationInfo::AllocationInfo(size_t bytes)
|
| + : bytes(bytes), locked(false) {}
|
|
|
| -// This is admittedly pretty magical. It's approximately enough memory for four
|
| -// 2560x1600 images.
|
| -static const size_t kDefaultDiscardableMemoryLimit = 64 * 1024 * 1024;
|
| -static const size_t kDefaultBytesToKeepUnderModeratePressure =
|
| - kDefaultDiscardableMemoryLimit / 4;
|
| +DiscardableMemoryManager::AllocationInfo::~AllocationInfo() {}
|
|
|
| -} // namespace
|
| -
|
| -DiscardableMemoryManager::DiscardableMemoryManager()
|
| - : allocations_(AllocationMap::NO_AUTO_EVICT),
|
| +DiscardableMemoryManager::DiscardableMemoryManager(
|
| + DiscardableMemoryAllocation::Factory* allocation_factory,
|
| + size_t discardable_memory_limit)
|
| + : allocation_factory_(allocation_factory),
|
| + next_allocation_id_(0),
|
| + allocations_(AllocationMap::NO_AUTO_EVICT),
|
| bytes_allocated_(0),
|
| - discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
|
| - bytes_to_keep_under_moderate_pressure_(
|
| - kDefaultBytesToKeepUnderModeratePressure) {
|
| -}
|
| + discardable_memory_limit_(discardable_memory_limit) {}
|
|
|
| DiscardableMemoryManager::~DiscardableMemoryManager() {
|
| DCHECK(allocations_.empty());
|
| DCHECK_EQ(0u, bytes_allocated_);
|
| }
|
|
|
| -void DiscardableMemoryManager::RegisterMemoryPressureListener() {
|
| - AutoLock lock(lock_);
|
| - DCHECK(base::MessageLoop::current());
|
| - DCHECK(!memory_pressure_listener_);
|
| - memory_pressure_listener_.reset(
|
| - new MemoryPressureListener(
|
| - base::Bind(&DiscardableMemoryManager::OnMemoryPressure,
|
| - Unretained(this))));
|
| -}
|
| -
|
| -void DiscardableMemoryManager::UnregisterMemoryPressureListener() {
|
| - AutoLock lock(lock_);
|
| - DCHECK(memory_pressure_listener_);
|
| - memory_pressure_listener_.reset();
|
| -}
|
| -
|
| void DiscardableMemoryManager::SetDiscardableMemoryLimit(size_t bytes) {
|
| AutoLock lock(lock_);
|
| discardable_memory_limit_ = bytes;
|
| EnforcePolicyWithLockAcquired();
|
| }
|
|
|
| -void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
|
| +DiscardableMemoryManager::AllocationId DiscardableMemoryManager::Register(
|
| size_t bytes) {
|
| AutoLock lock(lock_);
|
| - bytes_to_keep_under_moderate_pressure_ = bytes;
|
| -}
|
| -
|
| -void DiscardableMemoryManager::Register(
|
| - const DiscardableMemory* discardable, size_t bytes) {
|
| - AutoLock lock(lock_);
|
| + AllocationId allocation_id = next_allocation_id_++;
|
| + if (next_allocation_id_ == INT_MAX)
|
| + next_allocation_id_ = 1;
|
| // A registered memory listener is currently required. This DCHECK can be
|
| // moved or removed if we decide that it's useful to relax this condition.
|
| // TODO(reveman): Enable this DCHECK when skia and blink are able to
|
| // register memory pressure listeners. crbug.com/333907
|
| // DCHECK(memory_pressure_listener_);
|
| - DCHECK(allocations_.Peek(discardable) == allocations_.end());
|
| - allocations_.Put(discardable, Allocation(bytes));
|
| + DCHECK(allocations_.Peek(allocation_id) == allocations_.end());
|
| + allocations_.Put(allocation_id, AllocationInfo(bytes));
|
| + return allocation_id;
|
| }
|
|
|
| -void DiscardableMemoryManager::Unregister(
|
| - const DiscardableMemory* discardable) {
|
| +void DiscardableMemoryManager::Unregister(AllocationId allocation_id) {
|
| AutoLock lock(lock_);
|
| - AllocationMap::iterator it = allocations_.Peek(discardable);
|
| + AllocationMap::iterator it = allocations_.Peek(allocation_id);
|
| if (it == allocations_.end())
|
| return;
|
|
|
| - if (it->second.memory) {
|
| + if (it->second.allocation.get()) {
|
| size_t bytes = it->second.bytes;
|
| DCHECK_LE(bytes, bytes_allocated_);
|
| bytes_allocated_ -= bytes;
|
| - free(it->second.memory);
|
| + it->second.allocation.reset();
|
| }
|
| allocations_.Erase(it);
|
| }
|
|
|
| -scoped_ptr<uint8, FreeDeleter> DiscardableMemoryManager::Acquire(
|
| - const DiscardableMemory* discardable,
|
| - bool* purged) {
|
| +void* DiscardableMemoryManager::Lock(AllocationId allocation_id, bool* purged) {
|
| AutoLock lock(lock_);
|
| // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
|
| // cache.
|
| - AllocationMap::iterator it = allocations_.Get(discardable);
|
| + AllocationMap::iterator it = allocations_.Get(allocation_id);
|
| CHECK(it != allocations_.end());
|
|
|
| - if (it->second.memory) {
|
| - scoped_ptr<uint8, FreeDeleter> memory(it->second.memory);
|
| - it->second.memory = NULL;
|
| - *purged = false;
|
| - return memory.Pass();
|
| + if (it->second.allocation.get()) {
|
| + DiscardableMemoryAllocation* allocation = it->second.allocation.get();
|
| +
|
| + DCHECK(!it->second.locked);
|
| + it->second.locked = true;
|
| + *purged = !allocation->Lock();
|
| + return allocation->Memory();
|
| }
|
|
|
| size_t bytes = it->second.bytes;
|
| if (!bytes)
|
| - return scoped_ptr<uint8, FreeDeleter>();
|
| + return NULL;
|
|
|
| if (discardable_memory_limit_) {
|
| size_t limit = 0;
|
| @@ -123,49 +98,51 @@ scoped_ptr<uint8, FreeDeleter> DiscardableMemoryManager::Acquire(
|
|
|
| // Check for overflow.
|
| if (std::numeric_limits<size_t>::max() - bytes < bytes_allocated_)
|
| - return scoped_ptr<uint8, FreeDeleter>();
|
| + return NULL;
|
|
|
| - scoped_ptr<uint8, FreeDeleter> memory(static_cast<uint8*>(malloc(bytes)));
|
| - if (!memory)
|
| - return scoped_ptr<uint8, FreeDeleter>();
|
| + linked_ptr<DiscardableMemoryAllocation> allocation(
|
| + allocation_factory_->CreateLockedAllocation(bytes).release());
|
| + if (!allocation.get())
|
| + return NULL;
|
|
|
| + it->second.allocation = allocation;
|
| + it->second.locked = true;
|
| bytes_allocated_ += bytes;
|
| *purged = true;
|
| - return memory.Pass();
|
| + return allocation->Memory();
|
| }
|
|
|
| -void DiscardableMemoryManager::Release(
|
| - const DiscardableMemory* discardable,
|
| - scoped_ptr<uint8, FreeDeleter> memory) {
|
| +void DiscardableMemoryManager::Unlock(AllocationId allocation_id) {
|
| AutoLock lock(lock_);
|
| // NB: |allocations_| is an MRU cache, and use of |Get| here updates that
|
| // cache.
|
| - AllocationMap::iterator it = allocations_.Get(discardable);
|
| + AllocationMap::iterator it = allocations_.Get(allocation_id);
|
| CHECK(it != allocations_.end());
|
|
|
| - DCHECK(!it->second.memory);
|
| - it->second.memory = memory.release();
|
| -
|
| + DCHECK(it->second.allocation.get());
|
| + DCHECK(it->second.locked);
|
| + it->second.locked = false;
|
| + it->second.allocation->Unlock();
|
| EnforcePolicyWithLockAcquired();
|
| }
|
|
|
| -void DiscardableMemoryManager::PurgeAll() {
|
| +void DiscardableMemoryManager::PurgeUntilUsageIsWithin(size_t limit) {
|
| AutoLock lock(lock_);
|
| - PurgeLRUWithLockAcquiredUntilUsageIsWithin(0);
|
| + PurgeLRUWithLockAcquiredUntilUsageIsWithin(limit);
|
| }
|
|
|
| bool DiscardableMemoryManager::IsRegisteredForTest(
|
| - const DiscardableMemory* discardable) const {
|
| + AllocationId allocation_id) const {
|
| AutoLock lock(lock_);
|
| - AllocationMap::const_iterator it = allocations_.Peek(discardable);
|
| + AllocationMap::const_iterator it = allocations_.Peek(allocation_id);
|
| return it != allocations_.end();
|
| }
|
|
|
| bool DiscardableMemoryManager::CanBePurgedForTest(
|
| - const DiscardableMemory* discardable) const {
|
| + AllocationId allocation_id) const {
|
| AutoLock lock(lock_);
|
| - AllocationMap::const_iterator it = allocations_.Peek(discardable);
|
| - return it != allocations_.end() && it->second.memory;
|
| + AllocationMap::const_iterator it = allocations_.Peek(allocation_id);
|
| + return it != allocations_.end() && !it->second.locked;
|
| }
|
|
|
| size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
|
| @@ -173,27 +150,6 @@ size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
|
| return bytes_allocated_;
|
| }
|
|
|
| -void DiscardableMemoryManager::OnMemoryPressure(
|
| - MemoryPressureListener::MemoryPressureLevel pressure_level) {
|
| - switch (pressure_level) {
|
| - case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
|
| - Purge();
|
| - return;
|
| - case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
|
| - PurgeAll();
|
| - return;
|
| - }
|
| -
|
| - NOTREACHED();
|
| -}
|
| -
|
| -void DiscardableMemoryManager::Purge() {
|
| - AutoLock lock(lock_);
|
| -
|
| - PurgeLRUWithLockAcquiredUntilUsageIsWithin(
|
| - bytes_to_keep_under_moderate_pressure_);
|
| -}
|
| -
|
| void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
|
| size_t limit) {
|
| TRACE_EVENT1(
|
| @@ -208,14 +164,15 @@ void DiscardableMemoryManager::PurgeLRUWithLockAcquiredUntilUsageIsWithin(
|
| ++it) {
|
| if (bytes_allocated_ <= limit)
|
| break;
|
| - if (!it->second.memory)
|
| + if (!it->second.allocation.get())
|
| + continue;
|
| + if (it->second.locked)
|
| continue;
|
|
|
| size_t bytes = it->second.bytes;
|
| DCHECK_LE(bytes, bytes_allocated_);
|
| bytes_allocated_ -= bytes;
|
| - free(it->second.memory);
|
| - it->second.memory = NULL;
|
| + it->second.allocation.reset();
|
| }
|
| }
|
|
|
|
|