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

Unified Diff: base/memory/discardable_memory_provider.cc

Issue 17106004: Add discardable memory emulation for non-android/mac platforms (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 6 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 side-by-side diff with in-line comments
Download patch
Index: base/memory/discardable_memory_provider.cc
diff --git a/base/memory/discardable_memory_provider.cc b/base/memory/discardable_memory_provider.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c77e854828d4cc9678b06263436554cc0c1b439c
--- /dev/null
+++ b/base/memory/discardable_memory_provider.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/discardable_memory_provider.h"
+
+#include "base/bind.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/mru_cache.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+namespace {
+
+// If this is given a valid value via SetInstanceForTest, this pointer will be
+// returned by GetInstance rather than the usual singleton.
+static base::DiscardableMemoryProvider* s_provider_for_test = NULL;
+
+// This is admittedly pretty magical. It's approximately enough memory for two
+// 2560x1600 images.
+static const size_t kDefaultDiscardableMemoryLimit = 32 * 1024 * 1024;
+static const size_t kDefaultBytesToReclaimUnderModeratePressure =
+ kDefaultDiscardableMemoryLimit / 2;
+
+} // namespace
+
+DiscardableMemoryProvider::DiscardableMemoryProvider()
+ : allocations_(AllocationMap::NO_AUTO_EVICT),
+ bytes_allocated_(0),
+ discardable_memory_limit_(kDefaultDiscardableMemoryLimit),
+ bytes_to_reclaim_under_moderate_pressure_(
+ kDefaultBytesToReclaimUnderModeratePressure),
+ memory_pressure_listener_(new MemoryPressureListener(
+ base::Bind(&DiscardableMemoryProvider::NotifyMemoryPressure))) {
+}
+
+DiscardableMemoryProvider::~DiscardableMemoryProvider() {
+ AutoLock lock(allocations_lock_);
+ AllocationMap::iterator it = allocations_.begin();
+ for (; it != allocations_.end(); ++it)
+ if (it->first->memory_)
+ it->first->Deallocate();
+}
+
+// static
+DiscardableMemoryProvider* DiscardableMemoryProvider::GetInstance() {
+ if (s_provider_for_test)
+ return s_provider_for_test;
+ return Singleton<DiscardableMemoryProvider>::get();
+}
+
+// static
+void DiscardableMemoryProvider::SetInstanceForTest(
+ DiscardableMemoryProvider* provider) {
+ s_provider_for_test = provider;
+}
+
+// static
+void DiscardableMemoryProvider::NotifyMemoryPressure(
+ MemoryPressureListener::MemoryPressureLevel pressureLevel) {
+ switch (pressureLevel) {
+ case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
+ DiscardableMemoryProvider::GetInstance()->PurgeLRU();
+ break;
+ case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
+ DiscardableMemoryProvider::GetInstance()->PurgeAll();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void DiscardableMemoryProvider::SetDiscardableMemoryLimit(size_t bytes) {
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ discardable_memory_limit_ = bytes;
+ }
+ EnforcePolicy();
+}
+
+size_t DiscardableMemoryProvider::discardable_memory_limit() const {
+ AutoLock lock(
+ const_cast<DiscardableMemoryProvider*>(this)->bytes_allocated_lock_);
+ return discardable_memory_limit_;
+}
+
+void DiscardableMemoryProvider::SetBytesToReclaimUnderModeratePressure(
+ size_t bytes) {
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ bytes_to_reclaim_under_moderate_pressure_ = bytes;
+ }
+ EnforcePolicy();
+}
+
+size_t DiscardableMemoryProvider::
+ bytes_to_reclaim_under_moderate_pressure() const {
+ AutoLock lock(
+ const_cast<DiscardableMemoryProvider*>(this)->bytes_allocated_lock_);
+ return bytes_to_reclaim_under_moderate_pressure_;
+}
+
+void DiscardableMemoryProvider::Register(DiscardableMemory* discardable) {
+ DCHECK(allocations_.Peek(discardable) == allocations_.end());
+ {
+ AutoLock lock(allocations_lock_);
+ allocations_.Put(discardable, true);
+ }
+ EnforcePolicy();
+}
+
+void DiscardableMemoryProvider::Unregister(DiscardableMemory* discardable) {
+ {
+ AutoLock lock(allocations_lock_);
+ AllocationMap::iterator it = allocations_.Peek(discardable);
+ if (it != allocations_.end())
+ allocations_.Erase(it);
+ }
+ EnforcePolicy();
+}
+
+void DiscardableMemoryProvider::DidAllocate(size_t bytes) {
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ bytes_allocated_ += bytes;
+ }
+ EnforcePolicy();
+}
+
+void DiscardableMemoryProvider::DidDeallocate(size_t bytes) {
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ DCHECK(bytes <= bytes_allocated_);
+ bytes_allocated_ -= bytes;
+ }
+ EnforcePolicy();
+}
+
+bool DiscardableMemoryProvider::DidAccess(DiscardableMemory* discardable) {
+ AutoLock lock(allocations_lock_);
+ AllocationMap::iterator it = allocations_.Get(discardable);
+ return it != allocations_.end();
+}
+
+void DiscardableMemoryProvider::PurgeAll() {
+ AutoLock lock(allocations_lock_);
+ AllocationMap::iterator it = allocations_.begin();
+ for (; it != allocations_.end(); ++it) {
+ if (it->first->memory_ && !it->first->is_locked()) {
+ it->first->Deallocate();
+ DCHECK(!it->first->memory_);
+ }
+ }
+}
+
+void DiscardableMemoryProvider::PurgeLRU() {
+ size_t limit = 0;
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ if (bytes_to_reclaim_under_moderate_pressure_ == 0)
+ return;
+
+ if (bytes_to_reclaim_under_moderate_pressure_ < discardable_memory_limit_)
+ limit = bytes_allocated_ - bytes_to_reclaim_under_moderate_pressure_;
+ }
+
+ AutoLock lock(allocations_lock_);
+ AllocationMap::reverse_iterator it = allocations_.rbegin();
+ for(; it != allocations_.rend(); ++it) {
+ if (!it->first->memory_ || it->first->is_locked())
+ continue;
+ it->first->Deallocate();
+ DCHECK(!it->first->memory_);
+ AutoLock bytes_lock(bytes_allocated_lock_);
+ if (bytes_allocated_ <= limit)
+ break;
+ }
+}
+
+void DiscardableMemoryProvider::EnforcePolicy() {
+ bool exceeded_bound = false;
+ {
+ AutoLock lock(bytes_allocated_lock_);
+ if (discardable_memory_limit_ == 0)
+ return;
+ exceeded_bound = bytes_allocated_ > discardable_memory_limit_;
+ }
+ if (exceeded_bound)
+ PurgeLRU();
+}
+
+} // namespace base

Powered by Google App Engine
This is Rietveld 408576698