blob: 136d4b80d11f0acc92ab1a533ddd9bd97b188036 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_COORDINATOR_MEMORY_CONSUMER_H_
#define BASE_MEMORY_COORDINATOR_MEMORY_CONSUMER_H_
#include <string>
#include <string_view>
#include "base/base_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory_coordinator/traits.h"
#include "base/sequence_checker.h"
namespace base {
// The MemoryConsumer is used to coordinate memory usage across all processes.
// By registering with the MemoryConsumerRegistry, instances of this class are
// notified when they should reduce or increase memory usage.
//
// Each consumer has a unique ID, and a set of traits. All registered consumers
// with the same unique ID are assumed to be equivalent and must have the exact
// same traits.
//
// Each consumer is assigned a memory usage limit; a percentage that indicates
// how much memory they are allowed to use. The memory coordinator policy does
// not prescribe what a 100% limit is. It is up to the implementer to determine
// what specific number should correspond to the 100% limit.
//
// For instance, if a developer determines that a cache size of 500 entries
// represents the optimal balance between performance and memory usage for a
// typical user on a standard machine, then a 100% memory limit would correspond
// to this size. A 50% memory limit would thus correspond to 250 entries. This
// example uses a linear interpolation, but this is not mandated.
//
// The percentage cannot be negative, but it is allowed to go over 100%, in
// which case the implementation should scale accordingly.
//
// Note that an implementation of `OnUpdateMemoryLimit()` should *not* release
// any memory. This function is intended to simply update an internal limit, and
// a consumer should wait for a subsequent call to `OnReleaseMemory()` to free
// any memory that exceeds that limit.
//
// Here is an example implementation for a consumer that manages a cache with a
// LRU eviction policy.
//
// class ExampleConsumer : public MemoryConsumer {
// public:
// // ...
//
// // MemoryConsumer:
// void OnUpdateMemoryLimit() override {
// // Update the maximum size of the cache, but don't decrease that maximum
// // size below its current size to avoid freeing memory.
// int new_max_size =
// std::max(cache_.size(), kDefaultCacheMaxSize * memory_limit() / 100);
// cache_.SetMaxSize(new_max_size);
// }
// void OnReleaseMemory() override {
// int new_max_size = kDefaultCacheMaxSize * memory_limit() / 100;
// cache_.SetMaxSizeAndEvictExtraEntries(new_max_size);
// }
//
// private:
// static constexpr int kDefaultCacheMaxSize = 500;
// LRUCache cache_;
// };
//
class BASE_EXPORT MemoryConsumer {
public:
virtual ~MemoryConsumer() = default;
// The memory limit, expressed as a percentage.
int memory_limit() const { return memory_limit_; }
// Same as `memory_limit`, but expressed as a ratio.
double memory_limit_ratio() const { return memory_limit_ / 100.0; }
protected:
// Invoked when memory above the current `memory_limit()` should be freed.
virtual void OnReleaseMemory() = 0;
// Invoked when the `memory_limit()` assigned to this instance is updated. See
// the class comment above for a detailed description of how this limit works.
virtual void OnUpdateMemoryLimit() = 0;
private:
friend class RegisteredMemoryConsumer;
friend class AsyncMemoryConsumerRegistration;
// Instructs this consumer to update its internal memory limit. See the class
// comment above for a detailed description of how this limit works.
void UpdateMemoryLimit(int percentage);
// Instructs this consumer to release memory that is above the current
// `memory_limit()`.
void ReleaseMemory();
int memory_limit_ = 100;
SEQUENCE_CHECKER(sequence_checker_);
};
// Similar to ScopedObservation, registers a MemoryConsumer with the global
// MemoryConsumerRegistry.
class BASE_EXPORT ScopedMemoryConsumerRegistration {
public:
ScopedMemoryConsumerRegistration(std::string_view consumer_id,
MemoryConsumerTraits traits,
MemoryConsumer* consumer);
ScopedMemoryConsumerRegistration(const ScopedMemoryConsumerRegistration&) =
delete;
ScopedMemoryConsumerRegistration& operator=(
const ScopedMemoryConsumerRegistration&) = delete;
~ScopedMemoryConsumerRegistration();
private:
std::string consumer_id_;
raw_ptr<MemoryConsumer> consumer_;
};
} // namespace base
#endif // BASE_MEMORY_COORDINATOR_MEMORY_CONSUMER_H_