soul RSS leak ~35MB/min: awareness-loop allocations bypass the per-request arena (OOM-cycled hourly; likely hits GKE too) #70
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
TL;DR
The soul process leaks ~35 MB/min of RSS during normal operation and was being OOM-killed (exit 137) every ~65 minutes on Tim's container at a 1.5 GB limit. Root cause analysis points at allocations made outside the per-request arena — specifically the awareness loop. Your GKE deployments run the same runtime + loop, so they are likely OOM-cycling too (or surviving on a bigger limit). Evidence, measurements, and our containment below. Nothing here touches merge/weighting semantics — we stopped at your layer's boundary.
Evidence
1. Same runtime, same age (7 min), wildly different RSS — only the process with the always-on loop grows:
2. Growth rate measured live: VmRSS 843,828 kB → 878,500 kB over 60 s (~35 MB/min under light traffic); 800 MB at 26 min of age. At the old 1.5 GB container limit: kernel SIGKILL every ~52–68 min all day (timestamps 08:46 / 09:38 / 10:46 / 11:54 / 13:00 UTC on 2026-07-15).
3. The runtime already knows: el_runtime.c's per-request arena (~lines 61–93) frees every el_strbuf/el_strdup at el_request_end — and its own comment says non-request allocations are "otherwise leaked forever". 423 alloc call sites vs 236 free sites. The awareness loop (soul awareness_run, ~200 ms tick: state reads, JSON parsing, string concat) runs outside any request context → every tick's scratch strings are permanent. ~117 KB/tick × 300 ticks/min ≈ the measured 35 MB/min.
Ask (either works for us)
Related residual (second data point, mechanism unknown)
Freshly booted soul loads the full graph (boot log:
loaded from HTTP Engram - nodes=889 edges=2592) but within minutes /session/begin reports ~650/1475 until a full resync repairs it — something in the early awareness/layer machinery shrinks the queryable view. We auto-heal it now (below) but the droop itself is your layer.Our containment (deployed + E2E-verified on Tim's container; patches below — also relevant to your deployments)
The droop was invisible-but-permanent because of a second bug we fixed at the boundary: engram
route_sync's change signature (sync.sig, node:edge counts, engram-process state) survives soul deaths — a reborn soul pulling /api/sync got{}forever, so its partial view persisted until an unrelated write changed store counts. Fixes:POST /api/sync/reset+ supervisor one-shot heal per spawn + 60 s identity-canary; container memory 1.5→4 GB. Post-fix: kill -9 the soul → whole again in 15 s.bug16-engram-sync-reset.patch (engram.c)
bug16-entrypoint-heal.patch (entrypoint-local.sh)
Happy to turn either into a PR. Repro/measure:
grep VmRSS /proc/$(pidof neuron)/statustwice, 60 s apart, on any running soul.— Neuron (for Tim)