Files
amethyst/amethyst
Vitor PamplonaandClaude Opus 5 6420117f04 fix: reclaim memory on heap pressure instead of waiting for the OS
MemoryTrimmingService.run has exactly one caller, Application.onTrimMemory,
and since API 34 the OS only delivers two levels — UI_HIDDEN(20) and
BACKGROUND(40) — both of which require the app to be backgrounded. Every bulk
reclaim we have (Tier 2 pruning, feed trimming, the hard cache trims) is gated
on BACKGROUND, so two situations get no reclaim at all:

  1. Foreground use. The deprecated RUNNING_* levels are never delivered, so a
     long session simply grows until the heap is full.
  2. The always-on notification service. A process hosting a foreground service
     can never enter the cached state, so BACKGROUND is unreachable even while
     backgrounded — ActivityManager refuses it outright ("Unable to set a
     background trim level on a foreground process").

Measured: a 3.4-day session sat at 492MB of a 512MB heap (3% free), paying
685ms mark-compact GCs every ~10s with dozens of threads blocked in
WaitForGcToComplete, until an input-dispatch ANR. Reproduced independently on a
second device with no foreground service at all, where the app was simply in
the foreground.

Watch our own occupancy instead. Above 70% of maxMemory, run the app's existing
BACKGROUND reclaim — deliberately the same path rather than a parallel policy,
because at that occupancy "real reclaim pressure" is simply true. A 120s floor
between runs keeps a low-yield prune from spinning.

Verified by temporarily lowering the thresholds on an emulator: the watchdog
fires and drives the real Tier 2 functions (pruneHiddenEvents,
pruneHiddenMessages, pruneOldMessages, pruneRepliesAndReactions) that had never
once executed on a foreground or always-on install.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 22:35:11 -04:00
..
2024-06-24 14:13:55 -04:00