blob: 9608552de61e84e86e6a88ad7829d21993fb2ceb [file]
// Copyright 2026 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_AVAILABLE_MEMORY_MONITOR_H_
#define BASE_MEMORY_AVAILABLE_MEMORY_MONITOR_H_
#include <optional>
#include "base/base_export.h"
#include "base/byte_size.h"
#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
namespace base {
// A singleton monitor that periodically polls the system for available memory.
//
// This class optimizes resource usage by only running the polling timer when
// there are active observers.
//
// Threading: This class is not thread-safe. It must be accessed and used
// exclusively on the main thread.
class BASE_EXPORT AvailableMemoryMonitor {
public:
// Represents a snapshot of system memory state at a specific point in time.
struct MemorySample {
base::TimeTicks timestamp;
base::ByteSize available_physical_bytes;
#if BUILDFLAG(IS_WIN)
// The following commit metrics are retrieved via the Windows MEMORYSTATUSEX
// API. For details on the underlying fields, see:
// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
// The maximum amount of memory the current process can commit. This is
// usually the system-wide available commit space, but can be smaller if
// the process is subject to a Job object quota (ullAvailPageFile).
base::ByteSize available_commit_bytes;
// The current committed memory limit for the system or the current process,
// whichever is smaller (ullTotalPageFile).
base::ByteSize total_commit_bytes;
#endif
};
class Observer : public base::CheckedObserver {
public:
// Called when a new memory sample is available.
virtual void OnAvailableMemoryUpdated(const MemorySample& sample) = 0;
};
// Returns the singleton instance.
static AvailableMemoryMonitor* Get();
AvailableMemoryMonitor(const AvailableMemoryMonitor&) = delete;
AvailableMemoryMonitor& operator=(const AvailableMemoryMonitor&) = delete;
// Adds an observer to the monitor. Starts the polling timer if it is not
// currently running.
//
// Note: This does NOT trigger an immediate callback to the observer. If the
// observer needs the current state immediately upon registration, it should
// call `GetLastSample()`.
void AddObserver(Observer* obs);
// Removes an observer from the monitor. Stops the polling timer if there are
// no remaining observers.
void RemoveObserver(Observer* obs);
// Returns the most recently computed memory sample, or std::nullopt if
// monitoring has not yet started or completed its first check.
std::optional<MemorySample> GetLastSample() const;
protected:
// Protected for testing.
AvailableMemoryMonitor();
virtual ~AvailableMemoryMonitor();
// Called periodically by |timer_| to update the cached memory state.
virtual void OnMemoryCheckTimer();
// Performs the actual system call to retrieve available memory.
// Virtual for testing.
virtual std::optional<MemorySample> ComputeAvailableMemory();
private:
friend class base::NoDestructor<AvailableMemoryMonitor>;
void StartPolling();
void StopPolling();
base::ObserverList<Observer> observers_;
base::RepeatingTimer timer_;
// Caches the last sample to support GetLastSample().
std::optional<MemorySample> last_sample_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace base
#endif // BASE_MEMORY_AVAILABLE_MEMORY_MONITOR_H_