fix(mem): lower LVGL hybrid PSRAM threshold 1024->256 (heap-starvation reboots)#39
fix(mem): lower LVGL hybrid PSRAM threshold 1024->256 (heap-starvation reboots)#39torlando-tech wants to merge 1 commit into
Conversation
…n reboots) Moves ~45KB of small LVGL allocations to PSRAM (internal free 71->116KB, largest contiguous 61->106KB), fixing the internal-heap starvation that made the LXST call/loopback pipeline intermittently fail to allocate and reboot mid-call. System-wide allocator tuning; no audio/clock coupling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UWZuYkHBRqNb6BZHV8sTG5
Greptile SummaryThis PR lowers the LVGL hybrid-allocator PSRAM threshold from 1024 to 256 bytes, routing more small LVGL objects (styles, labels, animation descriptors) into PSRAM to relieve internal-heap fragmentation and prevent mid-call reboots in the LXST audio pipeline.
Confidence Score: 3/5The threshold change achieves its stated goal of relieving internal-heap pressure, but it exposes a latent data-corruption bug in the realloc path that now fires frequently during normal LVGL operation. The realloc migration path (internal → PSRAM) frees the old block without copying its contents, returning a pointer to uninitialized memory. At 1024 bytes this almost never triggered in practice; at 256 bytes it will fire on any LVGL label or array that grows through a realloc — corrupting UI state silently rather than crashing predictably. The threshold change is the right direction for the heap-fragmentation problem, but shipping it without fixing the copy omission trades one instability (OOM reboots) for another (random heap corruption). lib/lv_mem_hybrid.h — the realloc cross-region migration paths at lines 68–74 and 78–86 both need a memcpy before the old pointer is freed. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["lv_mem_hybrid_realloc(ptr, size)"] --> B{"ptr == NULL?"}
B -- yes --> C["lv_mem_hybrid_alloc"]
B -- no --> D{"size == 0?"}
D -- yes --> E["free + return NULL"]
D -- no --> F{"IS_PSRAM_ADDR"}
F -- yes --> G["realloc in PSRAM"]
G -- fail --> H["malloc internal then free old WITHOUT copy"]
F -- no --> I{"size >= THRESHOLD now 256"}
I -- yes --> J["malloc PSRAM then free old WITHOUT copy"]
J -- fail --> K["realloc internal"]
I -- no --> K
K -- fail --> L["realloc PSRAM cross-region"]
style J fill:#ff6666,color:#fff
style H fill:#ff6666,color:#fff
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["lv_mem_hybrid_realloc(ptr, size)"] --> B{"ptr == NULL?"}
B -- yes --> C["lv_mem_hybrid_alloc"]
B -- no --> D{"size == 0?"}
D -- yes --> E["free + return NULL"]
D -- no --> F{"IS_PSRAM_ADDR"}
F -- yes --> G["realloc in PSRAM"]
G -- fail --> H["malloc internal then free old WITHOUT copy"]
F -- no --> I{"size >= THRESHOLD now 256"}
I -- yes --> J["malloc PSRAM then free old WITHOUT copy"]
J -- fail --> K["realloc internal"]
I -- no --> K
K -- fail --> L["realloc PSRAM cross-region"]
style J fill:#ff6666,color:#fff
style H fill:#ff6666,color:#fff
|
Lowers the LVGL hybrid-allocator PSRAM threshold 1024→256, moving ~45 KB of small LVGL allocations (styles, obj metadata, labels, anim descriptors) into PSRAM. This de-fragments the scarce internal heap (internal free 71→116 KB, largest contiguous block 61→106 KB) so the LXST call/loopback audio pipeline can allocate reliably during a call instead of intermittently failing and rebooting mid-call.
System-wide allocator tuning; no audio/clock coupling. Found during the LXST voice investigation.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UWZuYkHBRqNb6BZHV8sTG5