summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-11 21:09:37 +0000
committerreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-11 21:09:37 +0000
commit918d756c987231342c28121fda931ce79fcdddab (patch)
treed11536a5aca694d6cd36fefca959c1af116c02f8
parentd937eaa69c611d748cee5f0fdeb14954d2c057e5 (diff)
downloadchromium_src-918d756c987231342c28121fda931ce79fcdddab.zip
chromium_src-918d756c987231342c28121fda931ce79fcdddab.tar.gz
chromium_src-918d756c987231342c28121fda931ce79fcdddab.tar.bz2
base: Introduce an explicit call for reducing emulated discardable memory usage.
This removes the use of memory pressure signals from discardable memory system and instead introduces an explicit call for reducing emulated discardable memory that the renderer can call when all widgets are hidden until we have a better mechanism in place. BUG=398087 TEST=base_unittests,content_browsertests Review URL: https://codereview.chromium.org/448173002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288793 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/memory/discardable_memory.h8
-rw-r--r--base/memory/discardable_memory_android.cc15
-rw-r--r--base/memory/discardable_memory_emulated.cc16
-rw-r--r--base/memory/discardable_memory_emulated.h7
-rw-r--r--base/memory/discardable_memory_linux.cc10
-rw-r--r--base/memory/discardable_memory_mac.cc16
-rw-r--r--base/memory/discardable_memory_manager.cc56
-rw-r--r--base/memory/discardable_memory_manager.h36
-rw-r--r--base/memory/discardable_memory_manager_unittest.cc41
-rw-r--r--base/memory/discardable_memory_unittest.cc10
-rw-r--r--base/memory/discardable_memory_win.cc10
-rw-r--r--content/renderer/render_thread_impl.cc14
-rw-r--r--content/renderer/render_thread_impl_browsertest.cc52
13 files changed, 98 insertions, 193 deletions
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
index d16ed3e..5b74705 100644
--- a/base/memory/discardable_memory.h
+++ b/base/memory/discardable_memory.h
@@ -64,14 +64,6 @@ class BASE_EXPORT DiscardableMemory {
public:
virtual ~DiscardableMemory() {}
- // Call this on a thread with a MessageLoop current to allow discardable
- // memory implementations to respond to memory pressure signals.
- static void RegisterMemoryPressureListeners();
-
- // Call this to prevent discardable memory implementations from responding
- // to memory pressure signals.
- static void UnregisterMemoryPressureListeners();
-
// Gets the discardable memory type with a given name.
static DiscardableMemoryType GetNamedType(const std::string& name);
diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc
index 8988c2b..acf29ac 100644
--- a/base/memory/discardable_memory_android.cc
+++ b/base/memory/discardable_memory_android.cc
@@ -32,10 +32,7 @@ size_t GetOptimalAshmemRegionSizeForAllocator() {
// Holds the shared state used for allocations.
struct SharedState {
SharedState()
- : manager(kAshmemMemoryLimit,
- kAshmemMemoryLimit,
- kAshmemMemoryLimit,
- TimeDelta::Max()),
+ : manager(kAshmemMemoryLimit, kAshmemMemoryLimit, TimeDelta::Max()),
allocator(kAshmemAllocatorName,
GetOptimalAshmemRegionSizeForAllocator()) {}
@@ -47,16 +44,6 @@ LazyInstance<SharedState>::Leaky g_shared_state = LAZY_INSTANCE_INITIALIZER;
} // namespace
// static
-void DiscardableMemory::RegisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
-}
-
-// static
-void DiscardableMemory::UnregisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
-}
-
-// static
bool DiscardableMemory::ReduceMemoryUsage() {
return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
}
diff --git a/base/memory/discardable_memory_emulated.cc b/base/memory/discardable_memory_emulated.cc
index 340a181..f9097b1 100644
--- a/base/memory/discardable_memory_emulated.cc
+++ b/base/memory/discardable_memory_emulated.cc
@@ -13,14 +13,12 @@ namespace {
// This is admittedly pretty magical.
const size_t kEmulatedMemoryLimit = 512 * 1024 * 1024;
const size_t kEmulatedSoftMemoryLimit = 32 * 1024 * 1024;
-const size_t kEmulatedBytesToKeepUnderModeratePressure = 4 * 1024 * 1024;
const size_t kEmulatedHardMemoryLimitExpirationTimeMs = 1000;
struct SharedState {
SharedState()
: manager(kEmulatedMemoryLimit,
kEmulatedSoftMemoryLimit,
- kEmulatedBytesToKeepUnderModeratePressure,
TimeDelta::FromMilliseconds(
kEmulatedHardMemoryLimitExpirationTimeMs)) {}
@@ -45,18 +43,14 @@ DiscardableMemoryEmulated::~DiscardableMemoryEmulated() {
}
// static
-void DiscardableMemoryEmulated::RegisterMemoryPressureListeners() {
- g_shared_state.Pointer()->manager.RegisterMemoryPressureListener();
-}
-
-// static
-void DiscardableMemoryEmulated::UnregisterMemoryPressureListeners() {
- g_shared_state.Pointer()->manager.UnregisterMemoryPressureListener();
+bool DiscardableMemoryEmulated::ReduceMemoryUsage() {
+ return g_shared_state.Pointer()->manager.ReduceMemoryUsage();
}
// static
-bool DiscardableMemoryEmulated::ReduceMemoryUsage() {
- return g_shared_state.Pointer()->manager.ReduceMemoryUsage();
+void DiscardableMemoryEmulated::ReduceMemoryUsageUntilWithinLimit(
+ size_t bytes) {
+ g_shared_state.Pointer()->manager.ReduceMemoryUsageUntilWithinLimit(bytes);
}
// static
diff --git a/base/memory/discardable_memory_emulated.h b/base/memory/discardable_memory_emulated.h
index 64e9951..d928513 100644
--- a/base/memory/discardable_memory_emulated.h
+++ b/base/memory/discardable_memory_emulated.h
@@ -19,10 +19,13 @@ class DiscardableMemoryEmulated
explicit DiscardableMemoryEmulated(size_t bytes);
virtual ~DiscardableMemoryEmulated();
- static void RegisterMemoryPressureListeners();
- static void UnregisterMemoryPressureListeners();
static bool ReduceMemoryUsage();
+ // TODO(reveman): Remove this as it is breaking the discardable memory design
+ // principle that implementations should not rely on information this is
+ // unavailable in kernel space. crbug.com/400423
+ BASE_EXPORT static void ReduceMemoryUsageUntilWithinLimit(size_t bytes);
+
static void PurgeForTesting();
bool Initialize();
diff --git a/base/memory/discardable_memory_linux.cc b/base/memory/discardable_memory_linux.cc
index b9342e9..578b2c1 100644
--- a/base/memory/discardable_memory_linux.cc
+++ b/base/memory/discardable_memory_linux.cc
@@ -11,16 +11,6 @@
namespace base {
// static
-void DiscardableMemory::RegisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
-}
-
-// static
-void DiscardableMemory::UnregisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
-}
-
-// static
bool DiscardableMemory::ReduceMemoryUsage() {
return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
}
diff --git a/base/memory/discardable_memory_mac.cc b/base/memory/discardable_memory_mac.cc
index b2184e7..fa6a231 100644
--- a/base/memory/discardable_memory_mac.cc
+++ b/base/memory/discardable_memory_mac.cc
@@ -25,11 +25,7 @@ namespace {
const size_t kMacMemoryLimit = 512 * 1024 * 1024;
struct SharedState {
- SharedState()
- : manager(kMacMemoryLimit,
- kMacMemoryLimit,
- kMacMemoryLimit,
- TimeDelta::Max()) {}
+ SharedState() : manager(kMacMemoryLimit, kMacMemoryLimit, TimeDelta::Max()) {}
internal::DiscardableMemoryManager manager;
};
@@ -160,16 +156,6 @@ class DiscardableMemoryMac
} // namespace
// static
-void DiscardableMemory::RegisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
-}
-
-// static
-void DiscardableMemory::UnregisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
-}
-
-// static
bool DiscardableMemory::ReduceMemoryUsage() {
return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
}
diff --git a/base/memory/discardable_memory_manager.cc b/base/memory/discardable_memory_manager.cc
index d976da2..3647b7b 100644
--- a/base/memory/discardable_memory_manager.cc
+++ b/base/memory/discardable_memory_manager.cc
@@ -18,14 +18,11 @@ namespace internal {
DiscardableMemoryManager::DiscardableMemoryManager(
size_t memory_limit,
size_t soft_memory_limit,
- size_t bytes_to_keep_under_moderate_pressure,
TimeDelta hard_memory_limit_expiration_time)
: allocations_(AllocationMap::NO_AUTO_EVICT),
bytes_allocated_(0u),
memory_limit_(memory_limit),
soft_memory_limit_(soft_memory_limit),
- bytes_to_keep_under_moderate_pressure_(
- bytes_to_keep_under_moderate_pressure),
hard_memory_limit_expiration_time_(hard_memory_limit_expiration_time) {
BytesAllocatedChanged(bytes_allocated_);
}
@@ -35,20 +32,6 @@ DiscardableMemoryManager::~DiscardableMemoryManager() {
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::SetMemoryLimit(size_t bytes) {
AutoLock lock(lock_);
memory_limit_ = bytes;
@@ -61,12 +44,6 @@ void DiscardableMemoryManager::SetSoftMemoryLimit(size_t bytes) {
soft_memory_limit_ = bytes;
}
-void DiscardableMemoryManager::SetBytesToKeepUnderModeratePressure(
- size_t bytes) {
- AutoLock lock(lock_);
- bytes_to_keep_under_moderate_pressure_ = bytes;
-}
-
void DiscardableMemoryManager::SetHardMemoryLimitExpirationTime(
TimeDelta hard_memory_limit_expiration_time) {
AutoLock lock(lock_);
@@ -77,13 +54,14 @@ bool DiscardableMemoryManager::ReduceMemoryUsage() {
return PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit();
}
+void DiscardableMemoryManager::ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
+ AutoLock lock(lock_);
+ PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(Now(),
+ bytes);
+}
+
void DiscardableMemoryManager::Register(Allocation* allocation, size_t bytes) {
AutoLock lock(lock_);
- // 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(allocation) == allocations_.end());
allocations_.Put(allocation, AllocationInfo(bytes));
}
@@ -182,28 +160,6 @@ size_t DiscardableMemoryManager::GetBytesAllocatedForTest() const {
return bytes_allocated_;
}
-void DiscardableMemoryManager::OnMemoryPressure(
- MemoryPressureListener::MemoryPressureLevel pressure_level) {
- switch (pressure_level) {
- case MemoryPressureListener::MEMORY_PRESSURE_MODERATE:
- PurgeUntilWithinBytesToKeepUnderModeratePressure();
- return;
- case MemoryPressureListener::MEMORY_PRESSURE_CRITICAL:
- PurgeAll();
- return;
- }
-
- NOTREACHED();
-}
-
-void
-DiscardableMemoryManager::PurgeUntilWithinBytesToKeepUnderModeratePressure() {
- AutoLock lock(lock_);
-
- PurgeIfNotUsedSinceTimestampUntilUsageIsWithinLimitWithLockAcquired(
- Now(), bytes_to_keep_under_moderate_pressure_);
-}
-
bool DiscardableMemoryManager::
PurgeIfNotUsedSinceHardLimitCutoffUntilWithinSoftMemoryLimit() {
AutoLock lock(lock_);
diff --git a/base/memory/discardable_memory_manager.h b/base/memory/discardable_memory_manager.h
index a61f141..94b3c55 100644
--- a/base/memory/discardable_memory_manager.h
+++ b/base/memory/discardable_memory_manager.h
@@ -8,7 +8,6 @@
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/containers/mru_cache.h"
-#include "base/memory/memory_pressure_listener.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
@@ -60,27 +59,15 @@ namespace internal {
// of all allocation instances (in case they need to be purged), and the total
// amount of allocated memory (in case this forces a purge). When memory usage
// reaches the limit, the manager purges the LRU memory.
-//
-// When notified of memory pressure, the manager either purges the LRU memory --
-// if the pressure is moderate -- or all discardable memory if the pressure is
-// critical.
class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
public:
typedef DiscardableMemoryManagerAllocation Allocation;
DiscardableMemoryManager(size_t memory_limit,
size_t soft_memory_limit,
- size_t bytes_to_keep_under_moderate_pressure,
TimeDelta hard_memory_limit_expiration_time);
virtual ~DiscardableMemoryManager();
- // Call this to register memory pressure listener. Must be called on a thread
- // with a MessageLoop current.
- void RegisterMemoryPressureListener();
-
- // Call this to unregister memory pressure listener.
- void UnregisterMemoryPressureListener();
-
// The maximum number of bytes of memory that may be allocated before we force
// a purge.
void SetMemoryLimit(size_t bytes);
@@ -89,9 +76,6 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
// limit expiration time without getting purged.
void SetSoftMemoryLimit(size_t bytes);
- // Sets the amount of memory to keep when we're under moderate pressure.
- void SetBytesToKeepUnderModeratePressure(size_t bytes);
-
// Sets the memory usage cutoff time for hard memory limit.
void SetHardMemoryLimitExpirationTime(
TimeDelta hard_memory_limit_expiration_time);
@@ -101,6 +85,10 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
// have been used.
bool ReduceMemoryUsage();
+ // This can be called to attempt to reduce memory footprint until within
+ // limit for bytes to keep under moderate pressure.
+ void ReduceMemoryUsageUntilWithinLimit(size_t bytes);
+
// Adds the given allocation to the manager's collection.
void Register(Allocation* allocation, size_t bytes);
@@ -141,14 +129,6 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
};
typedef HashingMRUCache<Allocation*, AllocationInfo> AllocationMap;
- // This can be called as a hint that the system is under memory pressure.
- void OnMemoryPressure(
- MemoryPressureListener::MemoryPressureLevel pressure_level);
-
- // Purges memory until usage is less or equal to
- // |bytes_to_keep_under_moderate_pressure_|.
- void PurgeUntilWithinBytesToKeepUnderModeratePressure();
-
// Purges memory not used since |hard_memory_limit_expiration_time_| before
// "right now" until usage is less or equal to |soft_memory_limit_|.
// Returns true if total amount of memory is less or equal to soft memory
@@ -185,14 +165,6 @@ class BASE_EXPORT_PRIVATE DiscardableMemoryManager {
// notification.
size_t soft_memory_limit_;
- // Under moderate memory pressure, we will purge memory until usage is within
- // this limit.
- size_t bytes_to_keep_under_moderate_pressure_;
-
- // Allows us to be respond when the system reports that it is under memory
- // pressure.
- scoped_ptr<MemoryPressureListener> memory_pressure_listener_;
-
// Amount of time it takes for an allocation to become affected by
// |soft_memory_limit_|.
TimeDelta hard_memory_limit_expiration_time_;
diff --git a/base/memory/discardable_memory_manager_unittest.cc b/base/memory/discardable_memory_manager_unittest.cc
index ef5739a..674499f 100644
--- a/base/memory/discardable_memory_manager_unittest.cc
+++ b/base/memory/discardable_memory_manager_unittest.cc
@@ -5,7 +5,6 @@
#include "base/memory/discardable_memory_manager.h"
#include "base/bind.h"
-#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,7 +45,6 @@ class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation {
// something else needs to explicit set the limit.
const size_t kDefaultMemoryLimit = 1024;
const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit;
-const size_t kDefaultBytesToKeepUnderModeratePressure = kDefaultMemoryLimit;
class TestDiscardableMemoryManagerImpl
: public internal::DiscardableMemoryManager {
@@ -54,7 +52,6 @@ class TestDiscardableMemoryManagerImpl
TestDiscardableMemoryManagerImpl()
: DiscardableMemoryManager(kDefaultMemoryLimit,
kDefaultSoftMemoryLimit,
- kDefaultBytesToKeepUnderModeratePressure,
TimeDelta::Max()) {}
void SetNow(TimeTicks now) { now_ = now; }
@@ -68,9 +65,7 @@ class TestDiscardableMemoryManagerImpl
class DiscardableMemoryManagerTestBase {
public:
- DiscardableMemoryManagerTestBase() {
- manager_.RegisterMemoryPressureListener();
- }
+ DiscardableMemoryManagerTestBase() {}
protected:
enum LockStatus {
@@ -85,10 +80,6 @@ class DiscardableMemoryManagerTestBase {
void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
- void SetBytesToKeepUnderModeratePressure(size_t bytes) {
- manager_.SetBytesToKeepUnderModeratePressure(bytes);
- }
-
void SetHardMemoryLimitExpirationTime(TimeDelta time) {
manager_.SetHardMemoryLimitExpirationTime(time);
}
@@ -127,10 +118,15 @@ class DiscardableMemoryManagerTestBase {
void SetNow(TimeTicks now) { manager_.SetNow(now); }
+ void PurgeAll() { return manager_.PurgeAll(); }
+
bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
+ void ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
+ manager_.ReduceMemoryUsageUntilWithinLimit(bytes);
+ }
+
private:
- MessageLoopForIO message_loop_;
TestDiscardableMemoryManagerImpl manager_;
};
@@ -192,11 +188,7 @@ TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) {
EXPECT_TRUE(CanBePurged(&allocation));
// Force the system to purge.
- MemoryPressureListener::NotifyMemoryPressure(
- MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
-
- // Required because ObserverListThreadSafe notifies via PostTask.
- RunLoop().RunUntilIdle();
+ PurgeAll();
EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
EXPECT_FALSE(CanBePurged(&allocation));
@@ -301,17 +293,14 @@ class DiscardableMemoryManagerPermutationTest
TestAllocationImpl allocation_[3];
};
-// Verify that memory was discarded in the correct order after applying
-// memory pressure.
-TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) {
+// Verify that memory was discarded in the correct order after reducing usage to
+// limit.
+TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) {
RegisterAndUseAllocations();
- SetBytesToKeepUnderModeratePressure(1024);
SetMemoryLimit(2048);
- MemoryPressureListener::NotifyMemoryPressure(
- MemoryPressureListener::MEMORY_PRESSURE_MODERATE);
- RunLoop().RunUntilIdle();
+ ReduceMemoryUsageUntilWithinLimit(1024);
EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
@@ -326,7 +315,6 @@ TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) {
TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
RegisterAndUseAllocations();
- SetBytesToKeepUnderModeratePressure(1024);
SetMemoryLimit(2048);
EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
@@ -340,7 +328,6 @@ TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
// Verify that no more memory than necessary was discarded after changing
// memory limit.
TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
- SetBytesToKeepUnderModeratePressure(2048);
SetMemoryLimit(4096);
RegisterAndUseAllocations();
@@ -358,9 +345,7 @@ TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
RegisterAndUseAllocations();
- MemoryPressureListener::NotifyMemoryPressure(
- MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
- RunLoop().RunUntilIdle();
+ PurgeAll();
for (int i = 0; i < 3; ++i) {
if (i == 0)
diff --git a/base/memory/discardable_memory_unittest.cc b/base/memory/discardable_memory_unittest.cc
index dc0e2cd..516a96b 100644
--- a/base/memory/discardable_memory_unittest.cc
+++ b/base/memory/discardable_memory_unittest.cc
@@ -6,7 +6,6 @@
#include <algorithm>
-#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
@@ -19,12 +18,8 @@ namespace {
class DiscardableMemoryTest
: public testing::TestWithParam<DiscardableMemoryType> {
public:
- DiscardableMemoryTest() : message_loop_(MessageLoop::TYPE_IO) {
- // Register memory pressure listeners now that we have a message loop.
- DiscardableMemory::RegisterMemoryPressureListeners();
- }
+ DiscardableMemoryTest() {}
virtual ~DiscardableMemoryTest() {
- DiscardableMemory::UnregisterMemoryPressureListeners();
}
protected:
@@ -32,9 +27,6 @@ class DiscardableMemoryTest
return DiscardableMemory::CreateLockedMemoryWithType(
GetParam(), size).Pass();
}
-
- private:
- MessageLoop message_loop_;
};
const size_t kSize = 1024;
diff --git a/base/memory/discardable_memory_win.cc b/base/memory/discardable_memory_win.cc
index b9342e9..578b2c1 100644
--- a/base/memory/discardable_memory_win.cc
+++ b/base/memory/discardable_memory_win.cc
@@ -11,16 +11,6 @@
namespace base {
// static
-void DiscardableMemory::RegisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::RegisterMemoryPressureListeners();
-}
-
-// static
-void DiscardableMemory::UnregisterMemoryPressureListeners() {
- internal::DiscardableMemoryEmulated::UnregisterMemoryPressureListeners();
-}
-
-// static
bool DiscardableMemory::ReduceMemoryUsage() {
return internal::DiscardableMemoryEmulated::ReduceMemoryUsage();
}
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 37fa090..daff6bc 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -15,6 +15,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/discardable_memory.h"
+#include "base/memory/discardable_memory_emulated.h"
#include "base/memory/shared_memory.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
@@ -179,6 +180,9 @@ const int kMaxRasterThreads = 64;
// allocation that exceeds this limit.
const size_t kImageCacheSingleAllocationByteLimit = 64 * 1024 * 1024;
+const size_t kEmulatedDiscardableMemoryBytesToKeepWhenWidgetsHidden =
+ 4 * 1024 * 1024;
+
// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
// incorrectly from the wrong thread.
base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> >
@@ -545,10 +549,6 @@ void RenderThreadImpl::Init() {
base::DiscardableMemory::SetPreferredType(type);
- // Allow discardable memory implementations to register memory pressure
- // listeners.
- base::DiscardableMemory::RegisterMemoryPressureListeners();
-
// AllocateGpuMemoryBuffer must be used exclusively on one thread but
// it doesn't have to be the same thread RenderThreadImpl is created on.
allocate_gpu_memory_buffer_thread_checker_.DetachFromThread();
@@ -1623,6 +1623,12 @@ void RenderThreadImpl::WidgetHidden() {
hidden_widget_count_++;
if (widget_count_ && hidden_widget_count_ == widget_count_) {
+ // TODO(reveman): Remove this when we have a better mechanism to prevent
+ // total discardable memory used by all renderers from growing too large.
+ base::internal::DiscardableMemoryEmulated::
+ ReduceMemoryUsageUntilWithinLimit(
+ kEmulatedDiscardableMemoryBytesToKeepWhenWidgetsHidden);
+
if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
}
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index f5a0d1d..55a4379 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "base/command_line.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/scoped_vector.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
@@ -70,5 +72,55 @@ TEST_F(RenderThreadImplBrowserTest,
base::Bind(&CheckRenderThreadInputHandlerManager, thread));
}
+// Checks that emulated discardable memory is discarded when the last widget
+// is hidden.
+TEST_F(RenderThreadImplBrowserTest,
+ EmulatedDiscardableMemoryDiscardedWhenWidgetsHidden) {
+ ContentClient content_client;
+ ContentBrowserClient content_browser_client;
+ ContentRendererClient content_renderer_client;
+ SetContentClient(&content_client);
+ SetBrowserClientForTesting(&content_browser_client);
+ SetRendererClientForTesting(&content_renderer_client);
+ base::MessageLoopForIO message_loop_;
+
+ std::string channel_id =
+ IPC::Channel::GenerateVerifiedChannelID(std::string());
+ DummyListener dummy_listener;
+ scoped_ptr<IPC::Channel> channel(
+ IPC::Channel::CreateServer(channel_id, &dummy_listener));
+ ASSERT_TRUE(channel->Connect());
+
+ scoped_ptr<MockRenderProcess> mock_process(new MockRenderProcess);
+ // Owned by mock_process.
+ RenderThreadImpl* thread = new RenderThreadImpl(channel_id);
+ thread->EnsureWebKitInitialized();
+ thread->WidgetCreated();
+
+ // Allocate 128MB of discardable memory.
+ ScopedVector<base::DiscardableMemory> discardable_memory;
+ for (int i = 0; i < 32; ++i) {
+ discardable_memory.push_back(
+ base::DiscardableMemory::CreateLockedMemoryWithType(
+ base::DISCARDABLE_MEMORY_TYPE_EMULATED, 4 * 1024 * 1024).release());
+ ASSERT_TRUE(discardable_memory.back());
+ discardable_memory.back()->Unlock();
+ }
+
+ // Hide all widgets.
+ thread->WidgetHidden();
+
+ // Count how much memory is left, should be at most one block.
+ int blocks_left = 0;
+ for (auto iter = discardable_memory.begin(); iter != discardable_memory.end();
+ ++iter) {
+ if ((*iter)->Lock() == base::DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS)
+ ++blocks_left;
+ }
+ EXPECT_LE(blocks_left, 1);
+
+ thread->WidgetDestroyed();
+}
+
} // namespace
} // namespace content