Summary
meshtasticd (Linux/portduino build) grows its virtual address space without bound on long-uptime hosts. On two boxes in a 5-box fleet I observed VmPeak ~915 GB and VmSwap ~1.78 GB after 9–10 days of uptime, while VmRSS stayed at ~45 MB. The 1.78 GB of touched-then-swapped pages pegged one Pi 5's swap at 100% and starved the rest of the stack. A clean restart drops VmPeak back to ~280 MB and VmSwap to 0.
I'm filing this from the perspective of an operator running a small permanent NOC fleet — happy to instrument further if it helps narrow it down.
Environment
- Version:
meshtasticd 2.7.15 (all five fleet boxes are on the same build)
- OS: Debian / Raspberry Pi OS bookworm (trixie on one)
- Arch: aarch64
- Hardware: mix of Pi 4B (Cortex-A72), Pi 5 (Cortex-A76), and a Pi Zero 2 W (Cortex-A53)
- Service:
meshtasticd.service running long-lived as a systemd unit
- HATs: Various Meshtastic SX1262 HATs via SPI
Fleet snapshot at the time of investigation
| Box |
Hardware |
Preset |
User |
Uptime |
VmPeak |
VmSwap |
RSS |
| A |
Pi 5 |
LongFast |
root |
9d 7h |
927 GB |
1.42 GB |
437 MB |
| B |
Pi 5 |
LongFast |
root |
10d 11h |
915 GB |
1.78 GB |
45 MB |
| C |
Pi 4B |
LongFast |
root |
4d 11h |
714 MB |
1.7 MB |
10 MB |
| D |
Pi 4B |
SHORT_TURBO |
meshtasticd |
21d 5h |
714 MB |
0 |
18 MB |
| E |
Pi Zero 2 W |
SHORT_TURBO |
root |
9d 10h |
280 MB |
1.7 MB |
6 MB |
The pattern hits boxes A and B; doesn't hit box D despite the longest uptime (21 days). Same firmware version on every box.
Two variables correlate with the leak in this small sample:
- LongFast preset (higher packet rate, broader gossip) — both leaky boxes are on LongFast; both heavily-trafficked boxes leak; the two SHORT_TURBO boxes don't.
- Heavy local API polling — boxes A and B both have a local NOC stack hitting
/api/v1/fromradio?all=true and :4403 TCP on a continuous cycle. Boxes C/D/E don't have that polling pattern.
Box C is on LongFast but only 4 days uptime, so it's not yet to the threshold where A and B exhibited the leak. Worth retesting after another week.
Reproduction observations
On the leaky boxes, VmData was ~908 GB while VmRSS was 45 MB:
Name: meshtasticd
VmPeak: 915812448 kB
VmSize: 915804192 kB
VmRSS: 45232 kB
VmData: 908017456 kB
VmSwap: 1785328 kB
Threads: 6
This suggests sparse anonymous mappings — large committed-but-untouched virtual regions that don't add up to RSS, plus a smaller (but absolute-terms still significant) ~1.78 GB of pages that DID get touched and then got pushed to swap.
Threads stayed at 6 — this isn't a thread leak.
What the operator sees
Symptom on a 4 GB Pi 5: Swap: 2.0Gi / 2.0Gi (100% full) with all other processes running normally. Once swap saturates, meshtasticd's own pages start thrashing (continuous si/so activity in vmstat) and any latency-sensitive co-tenant on the box (local map server, dashboard, monitoring stack) degrades. Eventually load climbs and the box stops servicing inbound HTTP requests in time.
Recovery
sudo systemctl restart meshtasticd
Immediately frees VmSwap back to 0 and VmPeak back to ~280 MB. Radio API on :9443 is responsive again within ~10 seconds. No data loss observed on the radio side.
Mitigation in my fleet (operator workaround, not a fix)
I deployed a weekly meshtasticd-restart.timer to bound the growth at 7 days. Treating this as a band-aid until the underlying allocation pattern is found.
Hypothesis
I'm not deep in the firmware allocator paths, but the combination of:
- VmData ~900 GB (mostly uncommitted but reserved)
- VmRSS small but VmSwap multi-GB (touched-then-cold pages)
- Only triggered under high-traffic preset + heavy local API polling
…feels consistent with either (a) growing per-packet/per-route state that gets allocated and not freed (Router history, NodeDB, MQTT queue?), or (b) a glibc/jemalloc fragmentation pattern where freed allocations leave large arenas reserved but never returned to the OS. (a) would be a real leak; (b) would be malloc behavior that's only visible because of the workload.
Happy to capture /proc/$pid/smaps, /proc/$pid/maps, or attach a pmap snapshot from a leaky box if useful — I can rebuild the leak in a few days now that we've reset. Also happy to try MALLOC_ARENA_MAX=2 as a probe if that would help separate (a) from (b).
Related
Cross-link from operator-side ops memo: this triggered a cascade where my local NOC's cloud snapshot pipeline went stale for ~3h because the map service on the leaky box stopped responding under swap pressure. Not a meshtasticd bug per se, but the swap thrash made it the proximate cause.
Summary
meshtasticd(Linux/portduino build) grows its virtual address space without bound on long-uptime hosts. On two boxes in a 5-box fleet I observedVmPeak ~915 GBandVmSwap ~1.78 GBafter 9–10 days of uptime, whileVmRSSstayed at ~45 MB. The 1.78 GB of touched-then-swapped pages pegged one Pi 5's swap at 100% and starved the rest of the stack. A clean restart dropsVmPeakback to ~280 MB andVmSwapto 0.I'm filing this from the perspective of an operator running a small permanent NOC fleet — happy to instrument further if it helps narrow it down.
Environment
meshtasticd 2.7.15(all five fleet boxes are on the same build)meshtasticd.servicerunning long-lived as a systemd unitFleet snapshot at the time of investigation
The pattern hits boxes A and B; doesn't hit box D despite the longest uptime (21 days). Same firmware version on every box.
Two variables correlate with the leak in this small sample:
/api/v1/fromradio?all=trueand:4403TCP on a continuous cycle. Boxes C/D/E don't have that polling pattern.Box C is on LongFast but only 4 days uptime, so it's not yet to the threshold where A and B exhibited the leak. Worth retesting after another week.
Reproduction observations
On the leaky boxes,
VmDatawas ~908 GB whileVmRSSwas 45 MB:This suggests sparse anonymous mappings — large committed-but-untouched virtual regions that don't add up to RSS, plus a smaller (but absolute-terms still significant) ~1.78 GB of pages that DID get touched and then got pushed to swap.
Threadsstayed at 6 — this isn't a thread leak.What the operator sees
Symptom on a 4 GB Pi 5:
Swap: 2.0Gi / 2.0Gi(100% full) with all other processes running normally. Once swap saturates,meshtasticd's own pages start thrashing (continuoussi/soactivity invmstat) and any latency-sensitive co-tenant on the box (local map server, dashboard, monitoring stack) degrades. Eventually load climbs and the box stops servicing inbound HTTP requests in time.Recovery
Immediately frees
VmSwapback to 0 andVmPeakback to ~280 MB. Radio API on:9443is responsive again within ~10 seconds. No data loss observed on the radio side.Mitigation in my fleet (operator workaround, not a fix)
I deployed a weekly
meshtasticd-restart.timerto bound the growth at 7 days. Treating this as a band-aid until the underlying allocation pattern is found.Hypothesis
I'm not deep in the firmware allocator paths, but the combination of:
…feels consistent with either (a) growing per-packet/per-route state that gets allocated and not freed (Router history, NodeDB, MQTT queue?), or (b) a glibc/jemalloc fragmentation pattern where freed allocations leave large arenas reserved but never returned to the OS. (a) would be a real leak; (b) would be malloc behavior that's only visible because of the workload.
Happy to capture
/proc/$pid/smaps,/proc/$pid/maps, or attach apmapsnapshot from a leaky box if useful — I can rebuild the leak in a few days now that we've reset. Also happy to tryMALLOC_ARENA_MAX=2as a probe if that would help separate (a) from (b).Related
Cross-link from operator-side ops memo: this triggered a cascade where my local NOC's cloud snapshot pipeline went stale for ~3h because the map service on the leaky box stopped responding under swap pressure. Not a meshtasticd bug per se, but the swap thrash made it the proximate cause.