Index: base/memory/memory_pressure_monitor.h |
diff --git a/base/memory/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor.h |
index 90c94209653423aa29e714fbb4b7754b5e7a9bd3..01cfc3b2fa5fdbf3baf0ca2fd825d3d5c3aed473 100644 |
--- a/base/memory/memory_pressure_monitor.h |
+++ b/base/memory/memory_pressure_monitor.h |
@@ -7,11 +7,55 @@ |
#include "base/base_export.h" |
#include "base/memory/memory_pressure_listener.h" |
+#include "base/memory/memory_pressure_monitor.h" |
+ |
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) |
+#include "base/memory/weak_ptr.h" |
+#include "base/threading/thread_checker.h" |
+#include "base/timer/timer.h" |
+#endif |
+ |
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) |
+#include "base/gtest_prod_util.h" |
+#include "base/macros.h" |
+#endif |
+ |
+#if defined(OS_CHROMEOS) |
+#include "base/files/scoped_file.h" |
+#endif |
+ |
+#if defined(OS_WIN) |
+// To not pull in windows.h. |
+typedef struct _MEMORYSTATUSEX MEMORYSTATUSEX; |
+#endif |
+ |
+#if defined(OS_MACOSX) |
+#include <dispatch/dispatch.h> |
+ |
+// The following was added to <dispatch/source.h> after 10.8. |
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders |
+// reach 10.9 or higher. |
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL |
+ |
+#define DISPATCH_MEMORYPRESSURE_NORMAL 0x01 |
+#define DISPATCH_MEMORYPRESSURE_WARN 0x02 |
+#define DISPATCH_MEMORYPRESSURE_CRITICAL 0x04 |
+ |
+#endif // DISPATCH_MEMORYPRESSURE_NORMAL |
+#endif |
namespace base { |
-// TODO(chrisha): Make this a concrete class with per-OS implementations rather |
-// than an abstract base class. |
+class TestMemoryPressureMonitor; |
+ |
+#if defined(OS_MACOSX) |
+struct DispatchSourceSDeleter { |
+ void operator()(dispatch_source_s* ptr) { |
+ dispatch_source_cancel(ptr); |
+ dispatch_release(ptr); |
+ } |
+}; |
+#endif |
// Declares the interface for a MemoryPressureMonitor. There are multiple |
// OS specific implementations of this class. An instance of the memory |
@@ -28,14 +72,214 @@ class BASE_EXPORT MemoryPressureMonitor { |
// Return the singleton MemoryPressureMonitor. |
static MemoryPressureMonitor* Get(); |
- // Returns the currently observed memory pressure. |
- virtual MemoryPressureLevel GetCurrentPressureLevel() const = 0; |
+ // Get the current memory pressure level. |
+ virtual MemoryPressureLevel GetCurrentPressureLevel() const; |
- protected: |
+#if defined(OS_CHROMEOS) |
+ // There are two memory pressure events: |
+ // MODERATE - which will mainly release caches. |
+ // CRITICAL - which will discard tabs. |
+ // The |MemoryPressureThresholds| enum selects the strategy of firing these |
+ // events: A conservative strategy will keep as much content in memory as |
+ // possible (causing the system to swap to zram) and an aggressive strategy |
+ // will release memory earlier to avoid swapping. |
+ enum MemoryPressureThresholds { |
+ // Use the system default. |
+ THRESHOLD_DEFAULT = 0, |
+ // Try to keep as much content in memory as possible. |
+ THRESHOLD_CONSERVATIVE = 1, |
+ // Discard caches earlier, allowing to keep more tabs in memory. |
+ THRESHOLD_AGGRESSIVE_CACHE_DISCARD = 2, |
+ // Discard tabs earlier, allowing the system to get faster. |
+ THRESHOLD_AGGRESSIVE_TAB_DISCARD = 3, |
+ // Discard caches and tabs earlier to allow the system to be faster. |
+ THRESHOLD_AGGRESSIVE = 4 |
+ }; |
+ MemoryPressureMonitor(MemoryPressureThresholds thresholds); |
+#endif |
+ |
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
MemoryPressureMonitor(); |
+#endif |
+ |
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) |
+ using GetUsedMemoryInPercentCallback = int (*)(); |
+ // Redo the memory pressure calculation soon and call again if a critical |
+ // memory pressure prevails. Note that this call will trigger an asynchronous |
+ // action which gives the system time to release memory back into the pool. |
+ void ScheduleEarlyCheck(); |
+#endif |
+ |
+#if defined(OS_WIN) |
+ // Constants governing the polling and hysteresis behaviour of the observer. |
+ |
+ // The polling interval, in milliseconds. While under critical pressure, this |
+ // is also the timer to repeat cleanup attempts. |
+ static const int kPollingIntervalMs; |
+ // The time which should pass between 2 successive moderate memory pressure |
+ // signals, in milliseconds. |
+ static const int kModeratePressureCooldownMs; |
+ // The number of cycles that should pass between 2 successive moderate memory |
+ // pressure signals. |
+ static const int kModeratePressureCooldownCycles; |
+ |
+ // Constants governing the memory pressure level detection. |
+ |
+ // The amount of total system memory beyond which a system is considered to be |
+ // a large-memory system. |
+ static const int kLargeMemoryThresholdMb; |
+ // Default minimum free memory thresholds for small-memory systems, in MB. |
+ static const int kSmallMemoryDefaultModerateThresholdMb; |
+ static const int kSmallMemoryDefaultCriticalThresholdMb; |
+ // Default minimum free memory thresholds for large-memory systems, in MB. |
+ static const int kLargeMemoryDefaultModerateThresholdMb; |
+ static const int kLargeMemoryDefaultCriticalThresholdMb; |
+ |
+ // Constructor with explicit memory thresholds. These represent the amount of |
+ // free memory below which the applicable memory pressure state engages. |
+ MemoryPressureMonitor(int moderate_threshold_mb, int critical_threshold_mb); |
+ |
+ // Schedules a memory pressure check to run soon. This must be called on the |
+ // same thread where the monitor was instantiated. |
+ void CheckMemoryPressureSoon(); |
+ |
+ // Returns the moderate pressure level free memory threshold, in MB. |
+ int moderate_threshold_mb() const { return moderate_threshold_mb_; } |
+ |
+ // Returns the critical pressure level free memory threshold, in MB. |
+ int critical_threshold_mb() const { return critical_threshold_mb_; } |
+#endif |
+ |
+ protected: |
+#if defined(OS_WIN) |
+ // Internals are exposed for unittests. |
+ |
+ // Automatically infers threshold values based on system memory. This invokes |
+ // GetMemoryStatus so it can be mocked in unittests. |
+ void InferThresholds(); |
+ |
+ // Starts observing the memory fill level. Calls to StartObserving should |
+ // always be matched with calls to StopObserving. |
+ void StartObserving(); |
+ |
+ // Stop observing the memory fill level. May be safely called if |
+ // StartObserving has not been called. Must be called from the same thread on |
+ // which the monitor was instantiated. |
+ void StopObserving(); |
+ |
+ // Checks memory pressure, storing the current level, applying any hysteresis |
+ // and emitting memory pressure level change signals as necessary. This |
+ // function is called periodically while the monitor is observing memory |
+ // pressure. This is split out from CheckMemoryPressureAndRecordStatistics so |
+ // that it may be called by CheckMemoryPressureSoon and not invoke UMA |
+ // logging. Must be called from the same thread on which the monitor was |
+ // instantiated. |
+ void CheckMemoryPressure(); |
+ |
+ // Wrapper to CheckMemoryPressure that also records the observed memory |
+ // pressure level via an UMA enumeration. This is the function that is called |
+ // periodically by the timer. Must be called from the same thread on which the |
+ // monitor was instantiated. |
+ void CheckMemoryPressureAndRecordStatistics(); |
+ |
+ // Calculates the current instantaneous memory pressure level. This does not |
+ // use any hysteresis and simply returns the result at the current moment. Can |
+ // be called on any thread. |
+ MemoryPressureLevel CalculateCurrentPressureLevel(); |
+ |
+ // Gets system memory status. This is virtual as a unittesting hook. Returns |
+ // true if the system call succeeds, false otherwise. Can be called on any |
+ // thread. |
+ virtual bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status); |
+#endif |
private: |
+ friend TestMemoryPressureMonitor; |
DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor); |
+ |
+ static MemoryPressureMonitor* g_monitor; |
+ |
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) |
+ friend TestMemoryPressureMonitor; |
+ // Starts observing the memory fill level. |
+ // Calls to StartObserving should always be matched with calls to |
+ // StopObserving. |
+ void StartObserving(); |
+ |
+ // Stop observing the memory fill level. |
+ // May be safely called if StartObserving has not been called. |
+ void StopObserving(); |
+ |
+ // The function which gets periodically called to check any changes in the |
+ // memory pressure. It will report pressure changes as well as continuous |
+ // critical pressure levels. |
+ void CheckMemoryPressure(); |
+ |
+ // The function periodically checks the memory pressure changes and records |
+ // the UMA histogram statistics for the current memory pressure level. |
+ void CheckMemoryPressureAndRecordStatistics(); |
+ |
+ // Get the memory pressure in percent (virtual for testing). |
+ virtual int GetUsedMemoryInPercent(); |
+ |
+ // The current memory pressure. |
+ base::MemoryPressureListener::MemoryPressureLevel |
+ current_memory_pressure_level_; |
+ |
+ // A periodic timer to check for resource pressure changes. This will get |
+ // replaced by a kernel triggered event system (see crbug.com/381196). |
+ base::RepeatingTimer<MemoryPressureMonitor> timer_; |
+ |
+ // To slow down the amount of moderate pressure event calls, this counter |
+ // gets used to count the number of events since the last event occured. |
+ int moderate_pressure_repeat_count_; |
+#endif |
+ |
+#if defined(OS_CHROMEOS) |
+ // The thresholds for moderate and critical pressure. |
+ const int moderate_pressure_threshold_percent_; |
+ const int critical_pressure_threshold_percent_; |
+ |
+ // File descriptor used to detect low memory condition. |
+ ScopedFD low_mem_file_; |
+#endif |
+ |
+#if defined(OS_WIN) |
+ // Threshold amounts of available memory that trigger pressure levels. See |
+ // memory_pressure_monitor.cc for a discussion of reasonable values for these. |
+ int moderate_threshold_mb_; |
+ int critical_threshold_mb_; |
+ |
+ // A periodic timer to check for memory pressure changes. |
+ base::RepeatingTimer<MemoryPressureMonitor> timer_; |
+ |
+ // The current memory pressure. |
+ MemoryPressureLevel current_memory_pressure_level_; |
+ |
+ // To slow down the amount of moderate pressure event calls, this gets used to |
+ // count the number of events since the last event occured. This is used by |
+ // |CheckMemoryPressure| to apply hysteresis on the raw results of |
+ // |CalculateCurrentPressureLevel|. |
+ int moderate_pressure_repeat_count_; |
+ |
+ // Ensures that this object is used from a single thread. |
+ base::ThreadChecker thread_checker_; |
+#endif |
+ |
+#if defined(OS_MACOSX) |
+ static MemoryPressureLevel MemoryPressureLevelForMacMemoryPressure( |
+ int mac_memory_pressure); |
+ static void NotifyMemoryPressureChanged(dispatch_source_s* event_source); |
+ |
+ scoped_ptr<dispatch_source_s, DispatchSourceSDeleter> |
+ memory_level_event_source_; |
+#endif |
+ |
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) |
+ // Weak pointer factory to ourself used for scheduling calls to |
+ // CheckMemoryPressure/CheckMemoryPressureAndRecordStatistics via |timer_|. |
+ base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_; |
+#endif |
}; |
} // namespace base |