blob: 75b08a64b6f82bb458c025017f8f79185e1d63ac [file] [log] [blame]
// Copyright 2015 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 "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h"
#include "base/allocator/partition_allocator/memory_reclaimer.h"
#include "base/feature_list.h"
#include "base/system/sys_info.h"
#include "base/trace_event/common/trace_event_common.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/renderer/platform/fonts/font_global_context.h"
#include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#if defined(OS_ANDROID)
#include "base/android/sys_utils.h"
#endif
namespace blink {
// Function defined in third_party/blink/public/web/blink.h.
void DecommitFreeableMemory() {
CHECK(IsMainThread());
base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
}
// static
bool MemoryPressureListenerRegistry::is_low_end_device_ = false;
// static
bool MemoryPressureListenerRegistry::IsLowEndDevice() {
return is_low_end_device_;
}
// static
bool MemoryPressureListenerRegistry::IsCurrentlyLowMemory() {
#if defined(OS_ANDROID)
return base::android::SysUtils::IsCurrentlyLowMemory();
#else
return false;
#endif
}
// static
void MemoryPressureListenerRegistry::Initialize() {
is_low_end_device_ = ::base::SysInfo::IsLowEndDevice();
ApproximatedDeviceMemory::Initialize();
// Make sure the instance of MemoryPressureListenerRegistry is created on
// the main thread. Otherwise we might try to create the instance on a
// thread which doesn't have ThreadState (e.g., the IO thread).
MemoryPressureListenerRegistry::Instance();
}
// static
void MemoryPressureListenerRegistry::SetIsLowEndDeviceForTesting(
bool is_low_end_device) {
is_low_end_device_ = is_low_end_device;
}
// static
MemoryPressureListenerRegistry& MemoryPressureListenerRegistry::Instance() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
CrossThreadPersistent<MemoryPressureListenerRegistry>, external,
(MakeGarbageCollected<MemoryPressureListenerRegistry>()));
return *external.Get();
}
void MemoryPressureListenerRegistry::RegisterThread(Thread* thread) {
MutexLocker lock(threads_mutex_);
threads_.insert(thread);
}
void MemoryPressureListenerRegistry::UnregisterThread(Thread* thread) {
MutexLocker lock(threads_mutex_);
threads_.erase(thread);
}
MemoryPressureListenerRegistry::MemoryPressureListenerRegistry() = default;
void MemoryPressureListenerRegistry::RegisterClient(
MemoryPressureListener* client) {
DCHECK(IsMainThread());
DCHECK(client);
DCHECK(!clients_.Contains(client));
clients_.insert(client);
}
void MemoryPressureListenerRegistry::UnregisterClient(
MemoryPressureListener* client) {
DCHECK(IsMainThread());
clients_.erase(client);
}
void MemoryPressureListenerRegistry::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) {
TRACE_EVENT1("blink", "MemoryPressureListenerRegistry::onMemoryPressure",
"level", level);
CHECK(IsMainThread());
for (auto& client : clients_)
client->OnMemoryPressure(level);
base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
}
void MemoryPressureListenerRegistry::OnPurgeMemory() {
CHECK(IsMainThread());
for (auto& client : clients_)
client->OnPurgeMemory();
ImageDecodingStore::Instance().Clear();
base::PartitionAllocMemoryReclaimer::Instance()->ReclaimAll();
// Thread-specific data never issues a layout, so we are safe here.
MutexLocker lock(threads_mutex_);
for (auto* thread : threads_) {
if (!thread->GetTaskRunner())
continue;
PostCrossThreadTask(
*thread->GetTaskRunner(), FROM_HERE,
CrossThreadBindOnce(
MemoryPressureListenerRegistry::ClearThreadSpecificMemory));
}
}
void MemoryPressureListenerRegistry::ClearThreadSpecificMemory() {
FontGlobalContext::ClearMemory();
}
void MemoryPressureListenerRegistry::Trace(Visitor* visitor) const {
visitor->Trace(clients_);
}
} // namespace blink