Leadaxe:解释 LxBox 内存占用机制与为何不使用 Rust 重写内核

Leadaxe 深入解释 LxBox 的内存行为与底层设计决策:Go 运行时不会立即向操作系统归还堆内存,常驻内存体现的是会话峰值而非泄漏;过低的内存上限反而会导致 GC 占满 CPU;同时阐明基于自维护 sing-box 分支迭代的合理性,不采用 Rust 重写内核。

作者原文

What you're describing is normal Go runtime behaviour, not a leak — and it's worth explaining because the number you're watching doesn't mean what it looks like.

Why RAM stays at ~400MB after you close the browser. Go does not return freed heap to the OS immediately. Memory that the collector has reclaimed stays mapped in the process and gets reused for the next allocations instead of being handed back and re-requested — that's cheaper than churning pages with the kernel. So RSS follows the high-water mark of your session, not the current number of connections. Going 340 → 430MB while a browser opens a few dozen connections, then settling near 400MB, is the runtime holding on to buffers it expects to need again. There is nothing to reclaim there; the memory is free from the program's point of view.

We did chase a real version of this, and it was the opposite problem. A hardcoded 200MB limit (v2.10.0) meant the collector ran continuously against a heap that couldn't fit — that was the "phone gets hot" reports, confirmed with a pprof CPU capture showing ~88% of CPU in GC. The fix was raising the ceiling, not lowering it.

So if you want to tune this: VPN Settings → System → Optimization → Memory limit. Default is Auto, which picks by device RAM (200/384/512MB). Lowering it will not reduce steady-state usage in a useful way — it makes the collector work harder for the same job. There's also Suspend idle tunnels in the same section, which cuts heap substantially when the device is idle.

On rewriting the kernel in Rust — no, and this isn't a performance judgement. LxBox runs on our own maintained fork of sing-box; that's what lets us debug all the way down and ship kernel fixes on our own schedule. Rewriting it would mean reimplementing every protocol, every transport and every routing behaviour from scratch, then re-verifying all of it on devices — years of work to arrive at the same feature set. The bottleneck in a proxy client is the network, not the language.