xref: /xnu-11215/doc/vm/memorystatus_notify.md (revision 8d741a5d)
1# Memorystatus Notifications
2
3This document details the notifications published by the memorystatus subsystem to userspace.
4
5## Dispatch Sources
6
7Handlers can be registered for pressure and limit notifications via the
8creation of a dispatch source of type `DISPATCH_SOURCE_TYPE_MEMORYPRESSURE`.
9See `dispatch_source_create(3)`.
10
11UIKit further exposes handlers for App
12developers. See
13[Responding to Low Memory Warnings](https://developer.apple.com/documentation/xcode/responding-to-low-memory-warnings).
14
15## Memory Limits
16
17Processes may subscribe to notifications regarding memory limits.
18
19| Type     | Knote Flags                             | Dispatch Source Mask                          | Description                                                                         |
20| -------- | --------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------- |
21| WARN     | `NOTE_MEMORYSTATUS_PROC_LIMIT_WARN`     | `DISPATCH_MEMORYPRESSURE_PROC_LIMIT_WARN`     | Process is within 100 MB of its memory limit.                                       |
22| CRITICAL | `NOTE_MEMORYSTATUS_PROC_LIMIT_CRITICAL` | `DISPATCH_MEMORYPRESSURE_PROC_LIMIT_CRITICAL` | Process has violated memory limit. Only sent if the memory limit is non-fatal/soft. |
23
24## Memory Pressure
25
26The kernel tracks its current "pressure level" via
27`memorystatus_vm_pressure_level`. There are 5 distinct levels of pressure:
28
29| Level      | Value | Knote Flags                           | Dispatch Source Mask               | Description                                                                              |
30| ---------- | ----- | ------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------- |
31| `Normal`   | 0     | `NOTE_MEMORYSTATUS_PRESSURE_NORMAL`   | `DISPATCH_MEMORYPRESSURE_NORMAL`   | Device is operating normally. No action is required.                                     |
32| `Warning`  | 1     | `NOTE_MEMORYSTATUS_PRESSURE_WARN`     | `DISPATCH_MEMORYPRESSURE_WARN`     | Device is beginning to experience memory pressure. Consider relaxing caching policy.     |
33| `Urgent`   | 2     | N/A                                   | N/A                                | Synonymous with `Warning`.                                                               |
34| `Critical` | 3     | `NOTE_MEMORYSTATUS_PRESSURE_CRITICAL` | `DISPATCH_MEMORYPRESSURE_CRITICAL` | Device is in a critical memory state. Expect latencies and consider dropping all caches. |
35| `Jetsam`\* | 4     | `NOTE_MEMORYSTATUS_JETSAM_FG_BAND`    | `N/A`                              | Jetsam is approaching the FOREGROUND band.                                               |
36
37\*`Jetsam` is only subscribable by kernel threads.
38
39### Available Memory
40
41The VM monitors the amount of "available memory" , which comprises the following:
42
43```
44AVAILABLE_NON_COMPRESSED_MEMORY = (active + inactive + free + speculative)
45AVAILABLE_MEMORY = (AVAILABLE_NON_COMPRESSED_MEMORY + compressed)
46```
47
48In other words, `AVAILABLE_NON_COMPRESSED_MEMORY` tracks all of the memory on
49the system that is either free or reclaimable (everything that is not either
50wired, compressed, or stolen). `AVAILABLE_MEMORY` tracks all memory that
51is reclaimable, free, or being used to store compressed anonymous memory (i.e.
52not wired or stolen). Compressed anonymous memory may be further "reclaimed"
53via swapping or compaction, and thus is considered "available".
54
55### Pressure Thresholds
56
57Pressure states are triggered when `AVAILABLE_NON_COMPRESSED_MEMORY` dips
58below the following thresholds:
59
60| Level       | Rising Threshold                                     | Falling Threshold                                    |
61| ----------- | ---------------------------------------------------- | ---------------------------------------------------- |
62| `Warning`   | `VM_PAGE_COMPRESSOR_COMPACT_THRESHOLD`               | `1.2 * VM_PAGE_COMPRESSOR_COMPACT_THRESHOLD`         |
63| `Critical`  | `1.2 * VM_PAGE_COMPRESSOR_SWAP_UNTHROTTLE_THRESHOLD` | `1.4 * VM_PAGE_COMPRESSOR_SWAP_UNTHROTTLE_THRESHOLD` |
64
65These thresholds are described by:
66
67| Threshold                                      | Embedded Value            | macOS Value               | Description                                               |
68| ---------------------------------------------- | ------------------------- | ------------------------- | --------------------------------------------------------- |
69| `VM_PAGE_COMPRESSOR_COMPACT_THRESHOLD`         | `0.5 * AVAILABLE_MEMORY`  | `0.5 * AVAILABLE_MEMORY`  | Initiate minor-compaction of compressed segments.         |
70| `VM_PAGE_COMPRESSOR_SWAP_THRESHOLD`            | `0.3 * AVAILABLE_MEMORY`  | `0.4 * AVAILABLE_MEMORY`  | Begin major-compaction & swapping of compressed segments. |
71| `VM_PAGE_COMPRESSOR_SWAP_UNTHROTTLE_THRESHOLD` | `0.25 * AVAILABLE_MEMORY` | `0.29 * AVAILABLE_MEMORY` | Un-throttle the swapper thread.                           |
72
73###  Kernel Monitoring
74
75Kernel/kext threads may monitor the system pressure level via
76`mach_vm_pressure_level_monitor()` which allows the current pressure level to
77be queried or the calling thread to block until the pressure level changes.
78
79### Differences from Jetsam
80
81The jetsam control loop monitors a different measure of "available" memory
82(`memorystatus_available_pages`, see [memorystatus.md](memorystatus.md)).
83This available page count is the subset of `AVAILABLE_NON_COMPRESSED_MEMORY`
84that is fully-reclaimable -- (file-backed + free + secluded-over-target +
85purgeable). Jetsam monitors the ratio of these fully-reclaimable pages to
86_all_ pages (max_mem), rather than only "available" pages as monitored for
87pressure.
88
89The design goals of jetsam and vm_pressure can be thought of in the following
90way.
91
92Jetsam attempts to maintain a sufficiently large pool of
93fully-reclaimable memory to satisfy transient spikes in page demand. This pool
94need not be overly large; thus jetsam thresholds are generally on the order of
955%/10%/15% of max_mem.
96
97Conversely, vm_pressure attempts to maintain the amount of memory available to
98the working set of processes. On a healthy system, this should be at least a
99majority of the memory not otherwise wired down or stolen by the operating
100system. If overall memory demand is such that, even with compression, the
101working set no longer fits in available memory, then the system begins making
102room by notifying processes, dropping caches, defragmenting the compressor pool,
103and swapping to disk.
104
105## Low Swap Notifications (macOS only)
106
107When the compressor has exhausted its available space (VA or compressed-pages
108limit), it will notify registered process via `NOTE_MEMORYSTATUS_LOW_SWAP` /
109`DISPATCH_MEMORYPRESSURE_LOW_SWAP`. This notification is restricted to the
110root user.
111
112## MallocStackLogging
113
114MallocStackLogging (MSL) can enabled/disabled via the same memorystatus knote.
115The mask is `NOTE_MEMORYSTATUS_MSL_STATUS`/`DISPATCH_MEMORYPRESSURE_MSL_STATUS`.
116libdispatch registers a source with this type for all processes with a handler
117that calls into libmalloc to enable/disable MSL.
118