Summary
Follow-up to #2490. Retained-heap attribution of an isolated daemon shows which live Rust/C heap no resident owner charges. #2490's refresh starvation and the missing swap term are fixed separately; the components below are still uncharged and not released by any owner.
Evidence
Isolated daemon (debug tracedecay/production build with the system allocator so heaptrack sees every allocation), MemoryMax=6G, MemorySwapMax=1G, isolated HOME/TRACEDECAY_DATA_DIR. Corpus: depth-1 clone of master at cc5a895 (6,684 files). The snapshot was taken after the cold index sealed generation 1 and one refresh commit had been attempted (and refused on master). heaptrack 1.5 --raw; live bytes are counted at the kill point, grouped by call site.
| Component (live at snapshot) |
Bytes |
Allocations |
Owner today |
| Privacy credential regex lazy-DFA caches (one per regex per scanning thread) |
201,597,261 |
201,330 |
none |
Tree-sitter trees in the per-worktree SharedRetainedParsePool (256 docs, bound is on source bytes only) |
181,191,207 |
1,868,404 |
none |
| Tool / MCP / SDK catalog and schema caches (process-lifetime) |
130,039,371 |
996,287 |
none (fixed) |
Captured source byte pool (SharedCodeIndexBytePoolV1) |
101,735,806 |
51,887 |
ledger (snapshot charge) |
| Canonical serializer / extraction rows |
29,945,854 |
4,305 |
none |
| SQLite page cache, schema, statements |
21,142,019 |
126,815 |
none |
| Sealed manifest / retained text generation |
12,074,505 |
119,590 |
none |
| Other |
2,584,369 |
16,829 |
|
| Total live heap |
680,384,120 |
3,385,448 |
|
At that point the same process had RssAnon 2,423,068 kB plus VmSwap 1,037,368 kB, and no resident owner was charged. heaptrack's own trace tree (27.1M nodes) inflates the RSS, so the gap between RSS and live heap there is mostly heaptrack plus allocator retention. It is not live Rust state.
Production (mimalloc) debug build from the fix branch, same corpus and cap, cold index plus one admitted refresh (generation 2 sealed at the refresh commit): RssAnon 3,306,024 kB, VmSwap 1,048,448 kB, admission sample 4,483,579,904 B. Charged owners were decoded_generation 2,760,435,008 B, which leaves ≈1.6 GB above the charged owners.
What remains
- Retained parse trees: per worktree, bounded by document count, not charged. There is no truthful byte measure for tree-sitter trees today. Either (a) register the pool as a resident owner with a structural tree-bytes bound (node count × subtree layout) and release it idle or under pressure, or (b) stop retaining trees parsed by a cold full build. Only changed-file rebuilds benefit from retention.
- Regex caches: bounded by rules × concurrent scanners × the lazy-DFA cache capacity (2 MiB default), never released. Needs a measured decision: a bounded cache capacity or a shared scanner width. Hotpath before/after on the privacy scan is required before changing it.
- Fixed runtime allowance: the catalog caches (130 MB), SQLite, and allocator overhead need an allowance defined by the resident-memory authority. Then the charged-owners-plus-allowance invariant can be asserted against measured anon RSS.
- Graph activation under load: in the debug build on a loaded host,
graph publication probe deadline exceeded retries forever while the 2.76 GB decoded generation stays held for the retry. code_graph_serving stays pending.
Summary
Follow-up to #2490. Retained-heap attribution of an isolated daemon shows which live Rust/C heap no resident owner charges. #2490's refresh starvation and the missing swap term are fixed separately; the components below are still uncharged and not released by any owner.
Evidence
Isolated daemon (debug
tracedecay/productionbuild with the system allocator so heaptrack sees every allocation),MemoryMax=6G,MemorySwapMax=1G, isolatedHOME/TRACEDECAY_DATA_DIR. Corpus: depth-1 clone ofmasterat cc5a895 (6,684 files). The snapshot was taken after the cold index sealed generation 1 and one refresh commit had been attempted (and refused on master). heaptrack 1.5--raw; live bytes are counted at the kill point, grouped by call site.SharedRetainedParsePool(256 docs, bound is on source bytes only)SharedCodeIndexBytePoolV1)At that point the same process had
RssAnon2,423,068 kB plusVmSwap1,037,368 kB, and no resident owner was charged. heaptrack's own trace tree (27.1M nodes) inflates the RSS, so the gap between RSS and live heap there is mostly heaptrack plus allocator retention. It is not live Rust state.Production (mimalloc) debug build from the fix branch, same corpus and cap, cold index plus one admitted refresh (generation 2 sealed at the refresh commit):
RssAnon3,306,024 kB,VmSwap1,048,448 kB, admission sample 4,483,579,904 B. Charged owners weredecoded_generation2,760,435,008 B, which leaves ≈1.6 GB above the charged owners.What remains
graph publication probe deadline exceededretries forever while the 2.76 GB decoded generation stays held for the retry.code_graph_servingstayspending.