# What is the resource budget for a SuuntoPlus app, and what should we do when the firmware unloads one?
-
Suunto Race 2, FW 2.56.18. SuuntoPlus Editor v1.42.0.
I am building a
type: "device"sports app that holds a BLE GATT link to a companion phone app.
It works well on its own. What I cannot get right is coexisting with the rest of the watch, and
after a lot of log reading I do not think I can solve it without knowing numbers that are not
published anywhere.What happens
The failure scales exactly with the number of enabled apps. One session, one exercise:
enabled apps result 1 (mine) fine, indefinitely 2 (mine + a Store app) fine, survives repeated screen switching 3 (the documented maximum) my app is unloaded on the second round of screen switching 14:14:37 : EVT APPLICATION : Zapp <app2>:Enable <- second app 14:15:14 : EVT APPLICATION : Zapp <app3>:Enable <- third app 14:15:21 : EVT APPLICATION : Zapp <mine>:templ load ... <- switching screens 14:15:33 : EVT APPLICATION : Zapp <app2>:templ load ... 14:15:34 : EVT APPLICATION : Zapp <app3>:templ load ... 14:15:36 : TRC MAPS : Maps closed 14:15:36 : EVT APPLICATION : Zapp <app3>:templ load ... 14:15:36 : ERR APPLICATION : Zapp:relMemCb (exec:ui) 14:15:36 : EVT APPLICATION : Zapp <mine>:Disable 14:15:36 : ERR APPLICATION : Zapp 3:RelMem->unload 14:15:36 : ERR BLE : Ble:conn id not foundThe BLE disconnect on unload is documented and expected. The problem is that
Zapp <mine>:Enable
never appears again, so the connection cannot be rebuilt and the app is dead for the rest of the
exercise — with no message to the user. Note also that the app the firmware unloaded is not the
one that was churning: the third app mounted its template five times in twenty seconds.A pool the firmware itself reports as full
At exercise start, with only my app enabled and before any of the above:
14:12:54 : WRN WBMAIN : pool id:0 full! (S 140/140) 14:12:54 : ERR WBMAIN : (0) Removed 121 non critical - size now=47 14:12:55 : WRN WBMAIN : pool id:0 full! (S 140/140) 14:12:55 : ERR WBMAIN : (0) Removed 117 non critical - size now=31140 slots, full, twice, with one app running. I do not know what pool 0 is or whether it is
related to the eviction, and I cannot find it documented anywhere — but it is the only hard
number the system gives me about its own limits.It does not look like my footprint
Measured on the built blob — resident minified
main.jsplus the single mounted template:resident main.js5 986 B largest template (compiled .xml)6 379 B total 12.4 KB Over one day I cut my UI from 13 757 B to 8 666 B and reduced my module-scope function count from
32 to 19. The behaviour did not change at all. I am clearly optimising against a number I
cannot see, and I would like to stop guessing.What the documentation does not say
The reference bundled with Editor v1.42.0 (6 March 2026) does not mention memory anywhere. It
documents the API surface well, but there is nothing on:- how much of anything an app may use, or what the pools even are;
- what counts against them — the mounted template, JS loaded with
evalFile, subscriptions,
manifest outputs; - which patterns are safe to use continuously and which are not;
- what an app should do when the firmware takes resources back.
FW 2.50.26 (7 January 2026) lists “Number of SuuntoPlus apps in sport mode increased from two to
three”. So three concurrent apps is a shipped, advertised feature — but there is no guidance
anywhere on the budget that makes three apps work, and I am seeing failures with one.Questions
-
Is there a resource budget we should be building to? Even rough figures would change how we
work: what the pools are, roughly how large, and what counts against each. What is
pool id:0(140 slots), and what fills it? -
Does the map view compete with SuuntoPlus apps for the same pool? Every eviction in my logs
is adjacent to a map open/close. The map has grown a lot recently (contour lines, elevation
labels, place names, road and peak labels), and the style loaded here is 4 792 B / 75 layers. -
How does the firmware choose which app to unload, and can an app influence it? A
device
app holding a live connection loses more than a screen when it is unloaded. -
What is an app supposed to do after
RelMem->unload? Is there a supported way to be
re-enabled within the same exercise, or should we treat an eviction as terminal and design for
it? Right now I cannot even tell the user what happened. -
Is
Zapp X:Disablewithout a followingJS discardexpected to release the app’s JS
context? This matters a lot: if it does not, every eviction permanently costs shared heap and
the situation degrades across a session rather than staying constant. -
Are there recommended practices for the UI side? Specifically: driving a high-rate value
from a template — is$.subscribeinonActivatesafe across repeated template mounts, or
should<eval>with ascriptformatter always be preferred? Both appear in the docs; only one
of them survived my testing, and I found that out from watch logs rather than from the manual.
What would help most
A short “resource budget and recommended practices” section in the reference. Not internals — just
the numbers to build to and the patterns to avoid. Right now every developer rediscovers the same
limits one freeze at a time, and we cannot tell a platform limit from a bug in our own code.Happy to provide full logs, the built blob, or a minimal reproduction if that is useful.
-
Follow-up: I ran the test, and I can answer my own question 5. The eviction path does not
release the app’s JS context, and the shared heap is exhausted inside a single four-minute
exercise.Method: fresh reboot, one exercise, three apps enabled, triggering the eviction repeatedly by
switching screens and opening/closing the map. After each eviction I re-enabled my app from the
SuuntoPlus menu without ending the exercise.Four evictions in four minutes
# time how long my app survived after being enabled 1 14:48:40 118 s 2 14:49:07 14 s 3 14:49:57 33 s 4 14:50:27 15 s 118 s the first time, 21 s on average afterwards — an 87% collapse.
The heap is at 99.5%
Two lines from the firmware itself, 16 seconds before the first eviction:
14:48:24 : WRN UI_FRAMEWORK : JsTotMem 129980/133120 (97.6%) 14:48:29 : WRN UI_FRAMEWORK : JsTotMem 132412/133120 (99.5%)This is the only figure the system has ever given me about its own limits, and it is not
documented anywhere. An earlier report on this forum (topic 15490) describes the watch freezing
at essentially this same level.Nothing is ever released
None of the four evictions is followed by
JS discard. The first and only one in the whole
session appears at 14:50:35, when I stop the exercise. So every
Disable→Load script→Enablecycle instantiates the module scope again while the previous
one is still held.That also reframes the “three apps” case. It is not that a third app is too big — my own
footprint is 12.4 KB, residentmain.jsplus the single mounted template. It is that three apps
cycling through evictions exhaust a shared pool that nothing empties until the exercise ends.One caveat on reading this
The intervals between evictions look almost constant (27, 50, 30 s). That number measures how
fast I re-enabled the app by hand, not the watch. Survival time is the honest metric.And the last three survival times being similar does not mean it stabilised — it means the pool
was already full before I started measuring. At 99.5%, any re-enable trips the release callback
almost immediately.So, concretely
- Is
Zapp X:Disablewithout a followingJS discardexpected to leak the module scope? If
yes, a firmware eviction is not a recoverable event — it permanently consumes shared heap, and
the watch degrades within a single session. - Is there a supported way to make an app release its context on eviction, or to be
re-enabled cleanly within the same exercise? - What is the intended budget per app against the 133 120 B shared heap when three apps are
enabled, which is the configuration FW 2.50.26 added?
I have the full logs and the built blob available if that helps, and I am happy to run any test
you would like measured. - Is
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login