FAQ
TL;DR: Fresh ESP32 NodeMCU boots with about 85 kB free heap; "heap shrinks to 45 kB after Ethernet" [Elektroda, TvWidget, post #18897727] Use node.heap() only for rough checks; rely on node.egc.meminfo() and pre-compiled .lc files to avoid resets.
Why it matters: Monitoring real heap head-room avoids silent crashes in memory-hungry IoT sketches.
Quick Facts
• Typical free heap after boot (Wi-Fi on, peripherals off): 80–90 kB [Elektroda, TvWidget, post #18897727]
• Ethernet driver buffers cost ≈40 kB, leaving ~45 kB heap [Elektroda, TvWidget, post #18897727]
• collectgarbage('count') showed 61.96 kB used → 62.32 kB after Ethernet [Elektroda, TvWidget, post #18897801]
• node.egc.setmode(ON_MEM_LIMIT, -6144) keeps ≥6 kB heap for C code [Elektroda, kogiel, post #19271316]
• Pre-compiled .lc bytecode cuts heap use by 20-25 % per module [NodeMCU Docs]
What value should node.heap() return right after a clean reset?
Most ESP32 NodeMCU builds report 80–90 kB free heap just after boot, before Wi-Fi or peripherals are initialised [Elektroda, TvWidget, post #18897727]
Why is node.heap() only a rough indicator?
node.heap() shows total free bytes, yet fragmentation can block big allocations. "Actual allocations of this size may not be possible" warns the API [Elektroda, khoam, post #18896278] Use node.egc.meminfo() for block-size detail.
How does collectgarbage('count') differ from node.heap()?
collectgarbage('count') returns Lua heap used, in kilobytes. Example: 61.96 kB before Ethernet and 62.32 kB after [Elektroda, TvWidget, post #18897801] node.heap() reports total free bytes, including C heap.
How much RAM does enabling Ethernet consume?
Starting LAN allocates about 40 kB for buffers and driver state, shrinking free heap from 85 kB to 45 kB [Elektroda, TvWidget, post #18897727]
Why do >2 kB strings fail after Ethernet starts?
With only ~45 kB free, heap fragmentation leaves no contiguous 2 kB block. Forcing an early small allocation sometimes rearranges memory and lets the big string succeed [Elektroda, TvWidget, post #18896784]
How can I immediately reclaim memory after using a Lua module?
- Set variable holding the module to nil.
- Call collectgarbage().
- Verify with node.heap() or node.egc.meminfo().
This 3-step frees the bytecode and data of the unused module.
Does collectgarbage() halt program execution?
It runs synchronously but quickly; the next Lua line executes once sweeping completes. If you set ‘setpause’ low (e.g., 50) the collector becomes more aggressive without noticeable blocking [Elektroda, khoam, post #18903644]
How do I set an automatic low-heap trigger?
Use node.egc.setmode(node.egc.ON_MEM_LIMIT, -6144). Lua then frees memory whenever free heap drops below 6 kB, keeping head-room for C functions [Elektroda, kogiel, post #19271316]
Does compiling Lua to .lc really save RAM?
Yes. Source text stays in flash; only compact bytecode loads, cutting heap by roughly 20–25 % per file [NodeMCU Docs]. One expert notes: “It is smaller in size, so it will also take up less RAM” [Elektroda, khoam, post #18901424]
What’s the safest way to pre-compile my scripts?
Compile on a PC with luac.cross, then upload the .lc files. This avoids in-device compilation overhead and further trims the image [NodeMCU Docs].
Why does writing to flash while Bluetooth scanning sometimes reset the ESP32?
Both operations use the SPI flash bus and BT controller simultaneously. Under heavy load the shared bus stalls, the watchdog fires, and the chip reboots—a documented edge-case in Espressif’s errata [Espressif Errata].
What happens if heap drops below 6 kB?
Lua C library calls may fail silently, causing unexpected resets with no error message—exactly the failure described when BT scanning and flash writes run together [Elektroda, TvWidget, post #18901499]