Skip to content

Apps cannot observe memory pressure: GetSystemStats is masked for third-party apps, and physical OOM is an uncatchable first-touch kill #12

Description

@ObjSal

Summary

Third-party apps have no way to observe memory pressure, and running out of physical memory is an uncatchable process kill. Together these make large-allocation workloads (image/PDF decoding, crypto) impossible to make robust: an app cannot check headroom before a big operation, cannot degrade gracefully, and cannot even report a useful error — it just dies with the crash screen.

Concretely:

  1. GetSystemStats(FreeMemory / IsSystemLowOnMemory) is denied to third-party apps — the syscall exists and does exactly what's needed (mm.ram_free()), but is_permitted_by_mask() filters it for sideloaded apps. Calling it returns an error.
  2. Physical OOM is unsurvivable by design: heap pages are demand-backed at first touch, so exhaustion surfaces as a data-abort in the middle of an ordinary write (often inside memclr of a fresh allocation) — no Err, no panic hook, no chance to free caches or show a message. try_reserve-style defensive coding can't help because the failure isn't at allocation time.

Why we hit this

Debugging a real crash (a third-party image viewer OOM-killed decoding a 6000×6000 JPEG on a 128 MB device — root cause turned out to be unbounded worker queues in a decoder crate, image-rs/jpeg-decoder#290) required building a dedicated diagnostic app that measures free RAM by mapping and touching 1 MB chunks until the probe itself is OOM-killed, reading the answer off the last painted frame. That worked (~59 MB free on our unit, stable across runs — page reclamation on process exit looks solid, for the record), but it's a destructive measurement no shipping app could ever do.

Ask

Any of these would help, in rough order of value:

  1. Permit GetSystemStats(FreeMemory) and IsSystemLowOnMemory in the third-party syscall mask. They're read-only and coarse; if a side channel is a concern, rounding FreeMemory (e.g. to 1 MB) would preserve the use case: "is there room for this decode?"
  2. A memory-pressure signal apps can subscribe to (the SystemEventHandler plumbing looks like a natural fit), so caches can be dropped before the kill.
  3. Longer-term: some way for an app to learn that a specific allocation cannot be backed — e.g. an opt-in "reserve = commit" mapping mode that fails the MapMemory call instead of the first touch — so try_reserve semantics become real on KeyOS.

Happy to provide the diagnostic app's source or test candidate builds on hardware.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions