mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
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>