Commit b121977b authored by Andreea Bacanu's avatar Andreea Bacanu Committed by Commit Bot

Clear the ClosedTabCache if memory is tight

Make ClosedTabCache listen to MemoryPressure listener and
flush the cache if the memory pressure level is critical.

Design doc:
https://docs.google.com/document/d/1SF230MYWgroe4WikDMn82ETd3-HFRzylKtIk0HZRaOU/edit?usp=sharing

BUG=1100946

Change-Id: I73afb124ab596ae9bd9db1bed84684088c174096
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352942Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Reviewed-by: default avatarSreeja Kamishetty <sreejakshetty@chromium.org>
Commit-Queue: Andreea Bacanu <aebacanu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800625}
parent 0fcda2a2
......@@ -21,6 +21,14 @@ static constexpr size_t kClosedTabCacheLimit = 1;
// The default time to live in seconds for entries in the ClosedTabCache.
static constexpr base::TimeDelta kDefaultTimeToLiveInClosedTabCacheInSeconds =
base::TimeDelta::FromSeconds(15);
// The memory pressure level from which we should evict all entries from the
// cache to preserve memory.
// TODO(https://crbug.com/1119368): Integrate memory pressure logic with
// PerformanceManager.
static constexpr base::MemoryPressureListener::MemoryPressureLevel
kClosedTabCacheMemoryPressureThreshold =
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
} // namespace
ClosedTabCache::Entry::Entry(SessionID id,
......@@ -32,7 +40,11 @@ ClosedTabCache::Entry::~Entry() = default;
ClosedTabCache::ClosedTabCache()
: cache_size_limit_(kClosedTabCacheLimit),
task_runner_(
content::GetUIThreadTaskRunner(content::BrowserTaskTraits())) {}
content::GetUIThreadTaskRunner(content::BrowserTaskTraits())) {
listener_ = std::make_unique<base::MemoryPressureListener>(
FROM_HERE, base::BindRepeating(&ClosedTabCache::OnMemoryPressure,
base::Unretained(this)));
}
ClosedTabCache::~ClosedTabCache() = default;
base::TimeDelta ClosedTabCache::GetTimeToLiveInClosedTabCache() {
......@@ -130,4 +142,15 @@ bool ClosedTabCache::IsEmpty() {
size_t ClosedTabCache::EntriesCount() {
return entries_.size();
}
void ClosedTabCache::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) {
if (level >= kClosedTabCacheMemoryPressureThreshold)
Flush();
}
void ClosedTabCache::Flush() {
TRACE_EVENT0("browser", "ClosedTabCache::Flush");
entries_.clear();
}
\ No newline at end of file
......@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_SESSIONS_CLOSED_TAB_CACHE_H_
#define CHROME_BROWSER_SESSIONS_CLOSED_TAB_CACHE_H_
#endif
#include <list>
#include <memory>
#include "base/memory/memory_pressure_listener.h"
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
......@@ -29,9 +29,7 @@ class WebContents;
// - evicts cache entries after a timeout.
// - evicts the least recently closed tab when the cache is full.
//
// TODO(aebacanu): Make ClosedTabCache listen to MemoryPressureListener and
// clear the cache if memory is tight. Hook ClosedTabCache into the navigation
// flow.
// TODO(aebacanu): Hook ClosedTabCache into the tab restore flow.
class ClosedTabCache {
public:
ClosedTabCache();
......@@ -98,6 +96,13 @@ class ClosedTabCache {
// nothing if the entry cannot be found.
void EvictEntryById(SessionID id);
// Flush the cache if memory is tight.
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level);
// Evict all entries from the ClosedTabCache.
void Flush();
// The set of stored Entries.
// Invariants:
// - Ordered from the most recently closed tab to the least recently closed.
......@@ -108,4 +113,10 @@ class ClosedTabCache {
// Task runner used for evicting cache entries after timeout.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
\ No newline at end of file
// Listener that sets up a callback to flush the cache if there is not enough
// memory available.
std::unique_ptr<base::MemoryPressureListener> listener_;
};
#endif // CHROME_BROWSER_SESSIONS_CLOSED_TAB_CACHE_H_
......@@ -4,8 +4,11 @@
#include "chrome/browser/sessions/closed_tab_cache.h"
#include "base/run_loop.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/util/memory_pressure/fake_memory_pressure_monitor.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
......@@ -32,6 +35,8 @@ class ClosedTabCacheTest : public InProcessBrowserTest {
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
}
util::test::FakeMemoryPressureMonitor fake_memory_pressure_monitor_;
};
// Add an entry to the cache when the cache is empty.
......@@ -193,4 +198,60 @@ IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, EvictEntryOnTimeout) {
// Expect the entry to have been evicted.
EXPECT_EQ(cache.EntriesCount(), 0U);
}
// Check that the cache is cleared if the memory pressure level is critical and
// the threshold is critical.
IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, MemoryPressureLevelCritical) {
ClosedTabCache cache;
AddTab(browser());
ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
std::unique_ptr<WebContents> wc =
browser()->tab_strip_model()->DetachWebContentsAt(0);
ASSERT_TRUE(cache.IsEmpty())
<< "Expected cache to be empty at the start of the test.";
cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
base::TimeTicks::Now());
EXPECT_EQ(cache.EntriesCount(), 1U);
fake_memory_pressure_monitor_.SetAndNotifyMemoryPressure(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
// Wait for all the pressure callbacks to be run.
base::RunLoop().RunUntilIdle();
// Expect the cache to have been cleared since the memory pressure level is
// at the threshold.
EXPECT_EQ(cache.EntriesCount(), 0U);
}
// Check that the cache is not cleared if the memory pressure level is moderate
// and the threshold is critical.
IN_PROC_BROWSER_TEST_F(ClosedTabCacheTest, MemoryPressureLevelModerate) {
ClosedTabCache cache;
AddTab(browser());
ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
std::unique_ptr<WebContents> wc =
browser()->tab_strip_model()->DetachWebContentsAt(0);
ASSERT_TRUE(cache.IsEmpty())
<< "Expected cache to be empty at the start of the test.";
cache.StoreEntry(SessionID::NewUnique(), std::move(wc),
base::TimeTicks::Now());
EXPECT_EQ(cache.EntriesCount(), 1U);
fake_memory_pressure_monitor_.SetAndNotifyMemoryPressure(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
base::RunLoop().RunUntilIdle();
// Expect the cache to not have been cleared since the memory pressure level
// is below the threshold.
EXPECT_EQ(cache.EntriesCount(), 1U);
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment