You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Back to Home from System restarts a 264 KB RP2040: the heap is too fragmented after System #49
On a Raspberry Pi RP2040 board (Waveshare RP2040-Touch-LCD-1.28, 240x240 GC9A01, MicroPython 1.30 preview, about 223 KB of heap), going back to Home from System restarts the board instead of switching. The launcher's heap check is what restarts it, so nothing crashes, but every return to Home costs a full boot.
To reproduce: put appkit, touchkit and the Home and System apps on the board as .mpy files, boot with appkit.run(), open System from Home's gear, then press Home.
Measured on that board after gc.collect():
State
Used
Free
Largest free block
Launcher baseline, first app start
127,472 B
113,120 B
Home open
115,264 B
112,704 B
about 86 KB
System open
144,480 B
83,488 B
about 22.6 KB
The launcher's thresholds come from that baseline: min_free 63,736 B and min_block 28,280 B, a quarter of the largest block. With System open, the biggest free block is already under 28 KB. Free memory is plentiful; it's the fragmentation that fails the check. LVGL's two draw buffers are 11,520 B each, so they aren't what holds the heap. Reading an AppScope's worker property while System is open also fails, with MemoryError allocating 24,576 B.
A side effect: System's Memory row reads gc.mem_free() between collections, so it can show "2 KB free, 220 KB used" while a collection would leave 83 KB free. That figure says the heap is full when it isn't.
What's still open is what fragments it. The candidates are the touchkit modules that System imports (touchkit.net, touchkit.settings and touchkit.shell load while System opens, and they stay after it closes), long-lived objects allocated in between System's LVGL widgets, and the code of the .mpy modules loaded into the heap. Possible fixes: import what System needs up front, before the baseline is measured; base min_block on what an app needs rather than on a quarter of the first measurement; or have the Memory row collect before it reads.
The switch was fragmenting the heap itself. The launcher checked the largest free block from inside the calls that delivered the switch. On this board call frames live on the heap, so those frames, the request's timer and its closure had all been allocated while the old app ran, and they split the space the close had just freed. System's close also imported wifi_manager, which then stayed loaded. Now a request uses two timers made with the launcher and closes the old app from the timer. The heap check and the next app's start run on the main loop's next turn, or from a scheduled call when nothing runs the loop. System's close no longer imports anything.
Measured on the Waveshare RP2040-Touch-LCD-1.28 by tapping through 20 Home-System round trips: no restart. The largest free block after each close stayed at 49-62 KB, and was 38 KB after the first close, while System's modules load. The threshold is 28 KB. Before the change it fell to 13 KB, and the board restarted within ten trips. Free heap after a close holds at 106 KB, so nothing leaks.
Activity
bdbarnett commentedon Nov 10, 2026
Fixed in #51, and the threshold is unchanged.
The switch was fragmenting the heap itself. The launcher checked the largest free block from inside the calls that delivered the switch. On this board call frames live on the heap, so those frames, the request's timer and its closure had all been allocated while the old app ran, and they split the space the close had just freed. System's close also imported
wifi_manager, which then stayed loaded. Now a request uses two timers made with the launcher and closes the old app from the timer. The heap check and the next app's start run on the main loop's next turn, or from a scheduled call when nothing runs the loop. System's close no longer imports anything.Measured on the Waveshare RP2040-Touch-LCD-1.28 by tapping through 20 Home-System round trips: no restart. The largest free block after each close stayed at 49-62 KB, and was 38 KB after the first close, while System's modules load. The threshold is 28 KB. Before the change it fell to 13 KB, and the board restarted within ten trips. Free heap after a close holds at 106 KB, so nothing leaks.