Memory Pressure Response
Chromium degrades its memory footprint in a predictable, ordered set of moves — tab discarding, renderer-process consolidation, GPU cache eviction, and per-renderer trim — when the OS reports available memory below platform-specific thresholds, trading specific guarantees of Site Isolation, the Rendering Pipeline, and the RAIL Performance Model for the survival of the user’s session on constrained hardware.
“Partial Site Isolation — Used on: Chrome for Android (2+ GB RAM).” — Chromium project, Process Model and Site Isolation, current
The user’s machine does not always have memory to spare. A six-year-old Android device running three other applications, a kiosk sized for one foreground site, and an Electron application competing with the user’s IDE all meet the same platform signal: available memory has crossed a threshold. The pattern is what Chromium does next. Its ordered responses name which guarantee is being traded, which symptom the user will see, and which diagnostic surface an engineer should inspect.
Context
A Chromium-based product is running on modest hardware: a low-end Android phone, an older Windows laptop in a corporate fleet, a Linux kiosk with deliberately constrained allocations, or an Electron application embedded inside a host that consumes most of the working set. Memory pressure is not an exceptional failure on these devices. It is the steady state. The platform’s MemoryPressureMonitor raises MEMORY_PRESSURE_LEVEL_MODERATE and MEMORY_PRESSURE_LEVEL_CRITICAL notifications against each OS’s native pressure signal, and the browser handles them before the OS chooses a harsher remedy. On Android, that harsher remedy is the low-memory killer terminating the browser process and losing every tab.
The pattern operates at the architectural scale of Multi-Process Architecture: renderer-process count, GPU cache size, and per-tab residency are first-order knobs. It also operates at the user-perception scale of the RAIL Performance Model: every move it makes has a user-visible consequence, and the pattern is, by design, choosing which user-visible consequence is least bad.
Problem
Memory is finite, the working set is not, and the OS does not negotiate. Three constraints meet without a clean resolution. The user expects open tabs to remain open and interactive. The project wants Site Isolation to hold so cross-origin data theft through Spectre-class speculative-execution side channels stays out of reach. The device may have enough memory for only a fraction of what the user loaded. Some property has to give. The pattern is the project’s encoded decision about which property gives, in what order, with what user-visible signal, and under what threshold.
Forces
- User session continuity. A user with twelve tabs open expects to find twelve tabs open when they return to the browser. Terminating tabs without warning loses unsaved form state, page scroll position, and (for some sites) the user’s logged-in session. The cost of a discard is real even when the page reloads cleanly.
- Security guarantee preservation. Site Isolation is a hard architectural commitment. Merging two cross-site renderers into one process re-opens the Spectre-class vector Site Isolation was built to close. The relaxation has to be the last move, not the first, and it has to be auditable.
- OS cooperation. If Chromium does nothing, the OS does something worse: Android’s low-memory killer terminates the foreground process; macOS pages aggressively to swap on a flash device whose write endurance the user cares about; Windows pages but also fires
LowMemoryResourcenotifications the browser cannot ignore. Cooperating with the OS is cheaper than being terminated by it. - Predictability for downstream products. An Electron application or a WebView2 integration that ships on enterprise hardware has to know what Chromium will do under pressure. An undocumented response means every customer support call about “the app froze” needs a Chromium-side investigation; a documented response means the integrator can ship a runbook.
- Per-platform variance. The thresholds, the available remediation steps, and the OS-side signal vary across Android, ChromeOS, Linux, Windows, and macOS. The pattern has to be portable across the differences while presenting one operational vocabulary.
Solution
Respond to memory pressure in a documented, ordered sequence whose steps escalate from cheap to expensive in user-perceptible cost and from preserving to relaxing in security guarantees. The canonical sequence below names the moves at four pressure levels, the platform-specific surface that triggers each, and the guarantee each move relaxes. Treat the order as the contract; treat the thresholds as Finch-tunable starting points the project varies by population per Finch Variations.
Level 1 — Background pre-discard hygiene. Before any pressure signal arrives, Chromium continuously evaluates which background tabs are the least recently used and pre-computes the cost of discarding each. The eviction policy in chrome/browser/resource_coordinator/tab_lifecycle_unit.cc accumulates the inputs (last-active timestamp, audible state, capturing-media state, form-state-present heuristic, pinned state). The move at this level is no move at all; it is the bookkeeping that makes the higher levels’ moves fast when the signal arrives.
Level 2 — Tab discarding. When the platform raises MEMORY_PRESSURE_LEVEL_MODERATE, Chromium discards the least valuable background tab. It serializes the tab’s session-storage state, terminates that tab’s renderer process, and leaves a tab-strip placeholder that reloads the page on focus. The user sees a tab strip whose entries persist, but the discarded page reloads when activated. The session is preserved; the resident set drops by roughly one renderer process plus its V8 heap. chrome://discards shows each tab’s discard score and whether the tab has been discarded since the session began.
Level 3 — Renderer process reuse and consolidation. When pressure persists after tab discards, or when Android is already operating under a constrained process budget, Chromium reuses renderer processes more aggressively. The Process Consolidation Under Memory Pressure pattern documents the trust-model side of that move. On desktop, the soft process limit pushes same-site process reuse before the browser creates more renderers. On Android, partial Site Isolation requires roughly a 2 GB-class device; the current source uses a 1900 MB default threshold for partial modes, a 3200 MB threshold for strict site-per-process mode, and Finch-tunable overrides. Below the partial threshold, Site Isolation is not available. At or above it, Chromium isolates sites likely to contain user-specific information rather than every site.
Level 4 — GPU cache eviction and renderer-internal trim. At MEMORY_PRESSURE_LEVEL_CRITICAL, the GPU process flushes caches: shader binaries, textures, command-buffer memory, and, on Graphite platforms, the pipeline cache that the Skia Graphite Transition pre-compiled at startup. The next animation frame pays the cost as shaders recompile, textures re-upload, and pipelines re-warm. The Animation budget the RAIL Performance Model declares is knowingly missed for that frame. Each renderer also receives a MemoryPressureListener::Notify callback and trims its own caches. V8 runs garbage collection, Blink drops style-cache entries, and the resource loader frees idle network connections. The pattern at this level chooses measurable RAIL violations over OOM kill.
Threshold values are platform-specific. Android’s Site Isolation threshold is not a single timeless number. The process-model documentation describes partial Site Isolation as available on Chrome for Android devices in the 2 GB RAM class and unavailable below that class; the current policy code uses 1900 MB for partial modes and 3200 MB for strict mode, with field-trial parameters able to move both. On desktop, memory-pressure thresholds derive from the MemoryPressureMonitor’s OS-native signal: kern.memorystatus_* sysctls on macOS, /proc/pressure/memory on Linux, and the LowMemoryResourceNotification event on Windows. The numbers move with hardware; the order of response does not.
How It Plays Out
A support engineer at an enterprise browser vendor receives a recurring report. Customers running the product on managed Pixel 4a devices (4 GB RAM, three other corporate applications in the background) say the browser feels different from the test phones. After twenty minutes of normal use, some tabs reload on activation, long articles stutter on the first scroll, and the password manager asks to unlock more often than expected. The team reads the report through the pattern. The reload is Level 2 discarding. The repeated unlock is a discarded tab losing in-memory state. The scroll stutter is a Level 4 Graphite pipeline-cache miss after pressure eases. The fix is at the deployment layer: reduce background tabs, close the chat application, or upgrade the fleet. The support response can name what Chromium is doing and why.
A security review of a Chromium-based product asks whether Site Isolation is fully enabled on the target Android population. The product team’s first answer is yes because Site Isolation is on at the build-config level. That is not the whole answer. On Android, low-memory devices below the partial Site Isolation threshold do not receive Site Isolation, and devices above it receive partial isolation for sites likely to hold user-specific information rather than desktop-style site-per-process isolation. Strict site-per-process mode has a higher memory threshold when enabled. The reviewer’s question has a precise answer: enabled where the device class and mode permit it; relaxed under documented thresholds; observable at chrome://memory-internals, chrome://process-internals, and chrome://discards/graph on the running browser.
A downstream Electron application ships with Chromium 130 and sees customer reports about freezes in the embedded webview during heavy use. The team’s first hypothesis is Main Thread Starvation, which would name a 50 ms Response-budget breach. The profile shows Level 3 consolidation: under the application’s working-set pressure, embedded Chromium has placed authentication, support-chat, and product-content documents into fewer renderer processes than the team expected. Main-thread contention in one surface registers as a freeze in another. The fix is at the application level: raise V8 heap headroom in the Electron launch flags, split support chat into a separate BrowserWindow, and add the application’s own memory-pressure observer in electron/main/. The pattern names the failure mode before the team chases the wrong root cause.
Consequences
Benefits. Sessions survive memory events that would otherwise terminate the browser. Tabs persist as identifiers across discards; users return to their work without rebuilding a window. The OS’s own remediation (Android’s low-memory-killer, Windows’ aggressive paging, macOS’s swap escalation) is held back, which saves the rest of the user’s working session even on devices where Chromium isn’t the only application competing. The pattern preserves the user-visible illusion that the browser has not crashed even under conditions where, without the pattern, a crash is what the OS would deliver.
Liabilities. Several architectural guarantees become conditional under the pattern. Site Isolation’s defense against cross-site Spectre-class leaks depends on platform, mode, and memory class. The RAIL Performance Model’s Animation budget depends on the GPU cache being warm. The Rendering Pipeline’s per-stage residency depends on no recent eviction. Any absolute claim about those guarantees needs an “absent memory pressure” qualifier.
Costs to plan for. Downstream Chromium-based products that target constrained hardware cannot ship without budgeting for the pattern’s effects. Discard-driven reload time is a recurring user complaint; the integrator’s choices (raise the discard score for tabs holding form state, pin specific tabs to non-discardable, increase the OS-reported memory budget if the host application can) move the curve. The pattern is the cost the rest of the architecture pays for survival.
Detection signals become composable. A team that has the pattern’s vocabulary can read the four levels’ signals as distinct: tab-discard rate is a Level 2 signal, consolidated-process count is a Level 3 signal, GPU cache miss rate is a Level 4 signal, and renderer-internal heap-trim frequency is the same signal at the per-tab granularity. The Perf Sheriff rotation routes regressions in each separately because the responding move differs.
The pattern relaxes; it doesn’t abandon. Even at Level 4 the Browser-Renderer Privilege Split is preserved: renderers may merge with each other but never merge into the browser process. The pattern releases specific isolation properties under threshold; it doesn’t abandon the trust-model architecture.
Notes for Agent Context
When generating code for a Chromium-based product targeting constrained hardware (Android below 4 GB RAM, embedded kiosk, Electron application with multiple concurrent renderers), wire a base::MemoryPressureListener into the application’s main process and respond to MEMORY_PRESSURE_LEVEL_MODERATE by trimming application-controlled caches before the platform’s tab discarder fires. Do not assume “the browser handles it.”
When asked whether a feature can rely on Site Isolation for cross-site secret containment, qualify the answer by platform, mode, and memory class. Desktop full Site Isolation is the strong case. On Android, partial Site Isolation starts at the 2 GB-class threshold documented by the process-model guide, and current policy code uses 1900 MB for partial modes and 3200 MB for strict mode, both field-trial tunable.
Never claim a per-frame Animation budget for code that runs immediately after a MEMORY_PRESSURE_LEVEL_CRITICAL notification. The GPU pipeline cache and texture cache may have just been flushed, so instrument the post-pressure frame separately.
When writing a Mojo IPC handler whose contract assumes a per-site renderer, audit the handler for safety under renderer consolidation. Cross-site state that traveled via a SiteInstance boundary inside one renderer process is the threat model consolidation widens, and RenderFrameHost::GetSiteInstance()->GetSiteInfo() must remain the trust source even when unrelated sites share a process.
Related Patterns
Sources
The canonical project description of the pressure-response architecture is docs/memory/README.md on chromium.googlesource.com, which enumerates the memory-tooling surfaces (chrome://memory-internals, chrome://discards, chrome://tracing memory-infra) every operator uses to read the pattern in action. The tab-discard policy is implemented in chrome/browser/resource_coordinator/tab_lifecycle_unit.cc and explained in the public ChromiumOS Tab Discarding and Reloading design note. The Site Isolation mode taxonomy and Android 2 GB-class threshold come from Chromium’s docs/process_model_and_site_isolation.md, while the current 1900 MB partial-mode and 3200 MB strict-mode defaults live in components/site_isolation/site_isolation_policy.cc. The memory-pressure notification vocabulary lives in base/memory/memory_pressure_listener.h and base/memory/memory_pressure_level.h. The public history is documented in the Chrome Security blog post Mitigating Spectre with Site Isolation (July 2018) and the Chrome 77 Android Site Isolation launch announcement (October 2019).
Technical Drill-Down
docs/memory/README.md(pinnedfb74f8d) — the in-tree memory documentation index; entry points to the discard policy, the pressure listener, and the renderer-internal trim hooks.base/memory/memory_pressure_listener.h(pinnedfb74f8d) — the cross-component subscription interface; every Chromium subsystem that releases cache memory under pressure registers here.base/memory/memory_pressure_level.h(pinnedfb74f8d) — theMEMORY_PRESSURE_LEVEL_MODERATEandMEMORY_PRESSURE_LEVEL_CRITICALenum values this pattern names.chrome/browser/resource_coordinator/tab_lifecycle_unit.cc(pinnedfb74f8d) — the Level 2 tab-discard implementation; the discard score logic and the per-tab eligibility table.docs/process_model_and_site_isolation.md(pinnedfb74f8d) — the current process-mode taxonomy; names desktop full Site Isolation, Android partial Site Isolation, low-memory Android no-Site-Isolation mode, andchrome://discards/graph.components/site_isolation/site_isolation_policy.cc(pinnedfb74f8d) — the Android threshold switchboard; current defaults are 1900 MB for partial modes and 3200 MB for strict site-per-process mode, with field-trial overrides.chrome://discardsandchrome://discards/graph— the running-browser operator surfaces for tab discard state and document-to-process mapping.- Chrome Security blog, Mitigating Spectre with Site Isolation, July 2018 — the public rationale for the per-site renderer model and the memory-overhead tradeoff that made Android rollout different from desktop rollout.
- Chromium blog, Recent Site Isolation improvements, October 2019 — the Android Site Isolation launch context and the password-sites-only fallback’s public framing.
- Chrome User Experience Report (CrUX) — memory dimension — the public dataset that aggregates field-measured device-class memory across the Chrome population; useful when planning how much of a product’s population sits near Android’s Site Isolation threshold classes.