Member-only story
TinyGo or no_std? Picking Embedded Paths That Scale
When ROM won’t fit your runtime and malloc might kill you, choosing between Go’s convenience and Rust’s control isn’t about preference — it’s about physics.
I spent three weeks debugging a sensor node that would crash every 47 hours. Not 48, not randomly — exactly 47 hours. The device read temperature data, sent it over LoRa, then went back to sleep. Simple, right?
Except I’d written it in TinyGo because “Go is easier,” and somewhere in that convenience, I’d introduced something worse than a leak — allocation churn that TinyGo’s non-moving mark-sweep collector couldn’t compact. Every sensor reading cycle allocated 200 bytes somewhere in that 256KB heap. The GC would dutifully mark and sweep, reclaim most of it, but those 40-byte fragmentation gaps? They just… stayed. Like debris after a flood that never quite drains.
Do the math with me here: 42,000 cycles over 47 hours, 200 bytes each. That’s 8.4MB of allocations churned through a 256KB space. The GC was working perfectly — it just couldn’t move things around to fill those gaps. Not a traditional memory leak. Something more insidious.
That failure taught me something I wish I’d learned earlier: embedded isn’t just “small…