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