You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Memory not released after indexing: 20GB+ RSS for 5MB of indexed data #832
After indexing a small project (65 files, 1.3MB, 2509 nodes), codebase-memory-mcp retains 20GB+ RSS on a 32GB Windows machine. Memory grows monotonically and is never released to the OS.
Environment
OS: Windows 11, i7-12700 (20 cores), 32GB RAM
CBM Version: 0.8.1
Project: 65 Markdown files, 1.3MB, 2509 nodes
Root Cause (from source code)
mimalloc abandoned-thread arenas not purged (mem.c missing mi_option_abandoned_thread_purge)
Default worker count uses all 20 cores, each with its own mimalloc arena
DEFAULT_RAM_FRACTION=0.5 means 16GB budget, no pressure to release
Observed memory
Without fix: 20GB+ RSS, growing 600MB/min, never releases
With workaround (CBM_WORKERS=1): 13MB stable
Thanks for the Windows memory-retention report and the before/after numbers. Triage: high-priority stability/performance issue under #593, with Windows impact.
This overlaps the memory-pressure work in #752/#685 but is more specific about post-index RSS retention and mimalloc worker-thread arenas. I see #833 is open against this; review should check that memory is actually returned after indexing without just hiding the issue by reducing worker parallelism too aggressively.
Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:
the codebase-memory-mcp --version you're on
the exact steps or command you ran
a public repo (or a small dummy snippet) that shows the problem — please don't paste proprietary code
Once that's here we'll pick it straight back up. Heads-up: issues left awaiting-reporter are automatically closed after a few weeks of silence, but a comment reopens the door anytime.
v0.9.0 includes memory-retention and RSS accounting fixes plus the indexing supervisor work, so this memory-retention report needs a fresh pass. Could you retest on v0.9.0 with the same project shape and share peak/live RSS if it still grows? Marking awaiting-reporter.
RSS growth over 5 min: ~0 MB (flat, no upward trend)
Committed: stable at 35.1 MB after initial query
Peak committed: 41.3 MB
Comparison
Previously on v0.8.1, two codebase-memory-mcp processes consumed 22.4 GB combined with CPU at 100%, growing over hours. On v0.9.0, RSS stays at ~17 MB with zero growth over 5 minutes.
The memory issue appears to be resolved in v0.9.0. The RSS is flat and memory is released back to the OS after indexing completes.
Confirming this is still present in 0.9.0 (Windows 11, 32GB RAM) — PR #831 was closed without merging (DCO/lint check failures unrelated to the code fix itself) so the root cause it identified is still live in the current release.
Repro on a real, public, large monorepo
Tested index_repository --mode fast on the llvm/ subdirectory of the public llvm-project monorepo (commit 9a2d9c7fef47c0af321150f75d8f21db06cccb43, ~80.8k files on disk, ~8.5k after language/ignore filtering) on a 32GB Windows 11 machine, default worker count (auto-detected, i7, 20 logical cores):
Worker RSS: 31MB → 9.5GB in ~3 min, then 10.7GB and still climbing ~1GB/min when I killed it (system free RAM dropped from 15GB to 5GB in the same window — this is a real stability risk, not just an inconvenience).
Setting CBM_WORKERS=1 before the same command on the same llvm/ tree changed the picture dramatically:
Peak RSS across three indexing attempts: ~4.4GB, ~4.7GB, ~6.3GB (vs. 10.7GB+ and climbing with default workers) — well inside the auto-detected 11.27GB budget the whole time, growth rate roughly linear and predictable instead of runaway.
System free RAM stayed in the 11–15GB range throughout instead of collapsing toward 0.
So the CBM_WORKERS=1 workaround from #831 is a solid, verified stopgap for large-repo Windows users. It doesn't get you to a successful index of llvm/ on its own though — see the hang/give-up issue in #1130, which I can also reproduce on this exact same public repo (details posted there) and which is the thing actually blocking a full index now that memory is controlled.
Would be happy to help get a rebased/DCO-signed version of #831's fix through CI if that'd unblock merging it — the diff itself looked correct in my read of src/foundation/mem.c / system_info.c.
Thanks for the current v0.9.0 LLVM measurement. It confirms that the small-repository flat-RSS result and the large-repository worker-arena growth are different regimes, and that CBM_WORKERS=1 is a useful temporary mitigation rather than a fix. Please hold off on rebasing #831 for now: we need to validate the allocator and worker-budget change against current main, Windows, and the supervisor behavior from #1130 before asking you to spend more contributor time.
The worker should either stay within the reported 2.85 GB budget or stop safely when it approaches that limit.
CBM_WORKERS=1 should reduce parallel overhead, but a single sequential pass should not be able to consume approximately 20 GB and exhaust Windows commit.
Notes
This is peak memory usage during indexing, not post-index retention: the run never completes.
With one worker, memory usage can still exceed the reported worker budget by approximately 7x.
I did not repeat the full workload with CBM_DIAGNOSTICS=1 because it was already bringing the machine close to instability. The measurements above came from Windows process and system counters.
I can collect a short diagnostic trace or test a diagnostic build if useful.
Thank you all three — @fxfxfx123 for the original reading of the mimalloc arena behaviour and a clean v0.9.0 retest showing the small-project case genuinely flat, @Khusan-Khujakeldiev for the public llvm/ measurement showing the large-repository case very much alive at ~1 GB/min, and @hetasshi for the v0.10.3 numbers that matter most.
@hetasshi's run is the important correction: ~20 GB RSS against a reported 2,852 MB budget with CBM_WORKERS=1 and mode=sequential. That rules out worker-arena multiplication as the whole story, because a single sequential pass has no business exceeding its own stated budget by roughly 7x, and the error: 1455 commit failures mean the run cannot complete at all on a 32 GB machine.
Honest status: not fixed. The budget is being reported but not enforced. Tonight's v0.10.5 is being cut for the issues that make cbm impossible to operate, and "indexing exhausts the machine and never produces an index" is one of them. Sorry for how much RAM and time this has consumed on your side.
Retested/observed on v0.10.8, Windows, 64 GB RAM. This is still capable of exhausting Windows commit.
Windows Resource-Exhaustion-Detector event 2004 recorded codebase-memory-mcp.exe as the largest virtual-memory consumer several times on 2026-08-24:
17:18:46: 25,812,156,416 bytes
17:53:59: 16,699,584,512 bytes
17:54:42: 16,923,176,960 bytes
18:01:29: 19,529,547,776 bytes
18:02:32: 21,508,403,200 bytes
The CBM daemon log selected budget_mb=32332 / memory_budget_bytes=33903435776, with auto_index=true and auto_watch=true. It also registered the broad session root D:\Workspace. Empty worker logs were created across the same three incident windows (.worker-11636.log, .worker-48652.log, .worker-14360.log), which ties the growth to indexing-worker activity rather than idle query use. Diagnostics were not enabled for those runs, so there is no retained RSS trajectory.
The machine had a manually constrained 16-64 MB pagefile, which made the resulting low-commit condition crash-prone, but does not explain a CBM process growing into the 16-25.8 GB range. Other applications have independently exhausted commit on this machine too.
Applied local containment while this remains open:
CBM_MEM_BUDGET_MB=4096
CBM_WORKERS=1
CBM_DIAGNOSTICS=1
auto_index=false
auto_watch=false
I will attach the diagnostic trajectory if the process exceeds the requested cap after all clients are restarted. No proprietary source or repository contents are included here.
Follow-up under the new containment profile (CBM_MEM_BUDGET_MB=4096, CBM_WORKERS=1, diagnostics enabled), with no indexing and auto-index/watch disabled:
I exercised 17 real MCP calls through one persistent v0.10.8 client against existing graphs, including:
list_projects, index_status
search_graph (BM25 and semantic)
search_code with full source
get_code_snippet, trace_path
check_index_coverage
get_architecture on 13k-node and 138k-node projects
bounded query_graph
The largest operation was MATCH (a)-[r:CALLS]->(b) RETURN count(r) on a 138,279-node / 462,750-edge graph. It peaked at about 992 MB RSS / 955 MB committed, then returned to about 17 MB RSS / 40 MB committed. Four identical sequential runs had the same peak and no rising settled baseline.
Experiment window:
start: 13.55 MB RSS / 37.38 MB committed
end after 17 calls: 16.72 MB RSS / 40.07 MB committed
process peak: 992.33 MB RSS / 955.23 MB committed
This does not reproduce a read-only query leak under sequential single-client use. It further narrows the prior 16-25.8 GB Windows events to indexing/worker activity (or a distinct multi-client concurrency path), rather than ordinary metadata/search/trace/Cypher use. Two calls submitted concurrently through one stdio client were serialized, so independent-client query concurrency remains untested.
Despite the reported 3 GiB worker cap, three successive indexing workers reached approximately 39.0, 39.0, and 40.3 GiB private bytes. At the system level, available memory fell to 351 MiB and committed memory reached 96.3 GiB before the indexing processes exited. No repository contents or private paths are included in these measurements.
The Windows subprocess supervisor currently creates a Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, but does not set a Job memory limit. The worker receives the budget through argv for internal accounting only, so Windows commit remains unconstrained if that accounting is exceeded.
PR #2030 adds JOB_OBJECT_LIMIT_JOB_MEMORY using the supervisor-calculated per-worker budget and includes a native Windows regression probe. It is intentionally a host-safety boundary, not a claim that the underlying indexing growth itself is fixed.
Thank you @experticket-admin for the fresh v0.10.8 measurements and for separating host containment from the underlying indexing growth.
A reported 3 GiB worker budget alongside roughly 39 to 40 GiB private-byte peaks is strong evidence that the current Windows supervisor budget is accounting rather than an OS enforcement boundary. PR #2030 is now routed as a high-priority Windows stability fix.
Because it changes Job Object limits and failure behavior for worker process trees, we need more time to review it carefully. No additional measurements are requested from you right now. Thank you for adding a native Windows probe instead of treating the limit as self-evident.
Fixed on main by #2112 (merge 1d66538). An over-budget index attempt now fails the whole attempt with a named error (CBM_PIPELINE_ABORT_OVER_BUDGET) after one back-pressure-futility confirmation cycle, instead of the old open-ended soft overshoot that let the kernel OOM-kill the worker. Staging is discarded through the existing rc≠0 path, so the previously serving index is kept byte-identical and no partial graph is published; the worker exits cleanly with a named reason (never a kill, so the supervisor no longer blames innocent files). The daemon also slices the worker memory budget by the number of active jobs. Thanks for the report — closing as fixed.
Activity
DeusData commentedon Jul 4, 2026
Thanks for the Windows memory-retention report and the before/after numbers. Triage: high-priority stability/performance issue under #593, with Windows impact.
This overlaps the memory-pressure work in #752/#685 but is more specific about post-index RSS retention and mimalloc worker-thread arenas. I see #833 is open against this; review should check that memory is actually returned after indexing without just hiding the issue by reducing worker parallelism too aggressively.
fix(index): gate supervised auto-index watcher registration on auto_w…
fix(index): run background auto-index + watcher re-index in the super…
github-actions commentedon Jul 8, 2026
Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:
codebase-memory-mcp --versionyou're onOnce that's here we'll pick it straight back up. Heads-up: issues left
awaiting-reporterare automatically closed after a few weeks of silence, but a comment reopens the door anytime.DeusData commentedon Jul 8, 2026
v0.9.0 includes memory-retention and RSS accounting fixes plus the indexing supervisor work, so this memory-retention report needs a fresh pass. Could you retest on v0.9.0 with the same project shape and share peak/live RSS if it still grows? Marking awaiting-reporter.
fxfxfx123 commentedon Jul 10, 2026
v0.9.0 Memory Test Report
Clean install of v0.9.0 (UI variant, Windows amd64), same project structure as before.
Environment
RSS Trajectory
Key Findings
Comparison
Previously on v0.8.1, two codebase-memory-mcp processes consumed 22.4 GB combined with CPU at 100%, growing over hours. On v0.9.0, RSS stays at ~17 MB with zero growth over 5 minutes.
The memory issue appears to be resolved in v0.9.0. The RSS is flat and memory is released back to the OS after indexing completes.
Khusan-Khujakeldiev commentedon Jul 23, 2026
Confirming this is still present in 0.9.0 (Windows 11, 32GB RAM) — PR #831 was closed without merging (DCO/lint check failures unrelated to the code fix itself) so the root cause it identified is still live in the current release.
Repro on a real, public, large monorepo
Tested
index_repository --mode faston thellvm/subdirectory of the public llvm-project monorepo (commit9a2d9c7fef47c0af321150f75d8f21db06cccb43, ~80.8k files on disk, ~8.5k after language/ignore filtering) on a 32GB Windows 11 machine, default worker count (auto-detected, i7, 20 logical cores):Workaround confirmed effective at this scale
Setting
CBM_WORKERS=1before the same command on the samellvm/tree changed the picture dramatically:So the
CBM_WORKERS=1workaround from #831 is a solid, verified stopgap for large-repo Windows users. It doesn't get you to a successful index ofllvm/on its own though — see the hang/give-up issue in #1130, which I can also reproduce on this exact same public repo (details posted there) and which is the thing actually blocking a full index now that memory is controlled.Would be happy to help get a rebased/DCO-signed version of #831's fix through CI if that'd unblock merging it — the diff itself looked correct in my read of
src/foundation/mem.c/system_info.c.DeusData commentedon Jul 24, 2026
Thanks for the current
v0.9.0LLVM measurement. It confirms that the small-repository flat-RSS result and the large-repository worker-arena growth are different regimes, and thatCBM_WORKERS=1is a useful temporary mitigation rather than a fix. Please hold off on rebasing #831 for now: we need to validate the allocator and worker-budget change against current main, Windows, and the supervisor behavior from #1130 before asking you to spend more contributor time.1 remaining item
hetasshi commentedon Aug 13, 2026
v0.10.3: worker memory budget exceeded during full indexing on Windows
I retested full indexing on v0.10.3. Memory usage still exceeds the reported worker budget by a large margin, even with
CBM_WORKERS=1.Environment
install.ps1Corpus
The tested Git worktree is 34 commits ahead of the public OpenJDK 21u commit
7da13d210d4c6024083c57f0b8432fc6fee19a90. The full run discovered 62,657 files.I have not yet reproduced this on a clean checkout of the upstream commit.
Reproduction
Default full run:
Full run with one worker. The daemon must be restarted because it reads environment variables at startup:
Results
Default run
workers=16andtotal_mb=2852 per_worker_mb=178.rss_mb=2930 budget_mb=2852 pct=102.cannot commit OS memory (error: 1455)andunable to commit meta-data.Run with
CBM_WORKERS=1workers=1andpipeline.mode mode=sequential.definitionspass, the worker reached approximately 20,170 MB RSS and 20,417 MB private memory.Expected behavior
The worker should either stay within the reported 2.85 GB budget or stop safely when it approaches that limit.
CBM_WORKERS=1should reduce parallel overhead, but a single sequential pass should not be able to consume approximately 20 GB and exhaust Windows commit.Notes
CBM_DIAGNOSTICS=1because it was already bringing the machine close to instability. The measurements above came from Windows process and system counters.DeusData commentedon Aug 14, 2026
Thank you all three — @fxfxfx123 for the original reading of the mimalloc arena behaviour and a clean v0.9.0 retest showing the small-project case genuinely flat, @Khusan-Khujakeldiev for the public
llvm/measurement showing the large-repository case very much alive at ~1 GB/min, and @hetasshi for the v0.10.3 numbers that matter most.@hetasshi's run is the important correction: ~20 GB RSS against a reported 2,852 MB budget with
CBM_WORKERS=1andmode=sequential. That rules out worker-arena multiplication as the whole story, because a single sequential pass has no business exceeding its own stated budget by roughly 7x, and theerror: 1455commit failures mean the run cannot complete at all on a 32 GB machine.Honest status: not fixed. The budget is being reported but not enforced. Tonight's v0.10.5 is being cut for the issues that make cbm impossible to operate, and "indexing exhausts the machine and never produces an index" is one of them. Sorry for how much RAM and time this has consumed on your side.
rarepops commentedon Aug 24, 2026
Retested/observed on v0.10.8, Windows, 64 GB RAM. This is still capable of exhausting Windows commit.
Windows Resource-Exhaustion-Detector event 2004 recorded
codebase-memory-mcp.exeas the largest virtual-memory consumer several times on 2026-08-24:The CBM daemon log selected
budget_mb=32332/memory_budget_bytes=33903435776, withauto_index=trueandauto_watch=true. It also registered the broad session rootD:\Workspace. Empty worker logs were created across the same three incident windows (.worker-11636.log,.worker-48652.log,.worker-14360.log), which ties the growth to indexing-worker activity rather than idle query use. Diagnostics were not enabled for those runs, so there is no retained RSS trajectory.The machine had a manually constrained 16-64 MB pagefile, which made the resulting low-commit condition crash-prone, but does not explain a CBM process growing into the 16-25.8 GB range. Other applications have independently exhausted commit on this machine too.
Applied local containment while this remains open:
CBM_MEM_BUDGET_MB=4096CBM_WORKERS=1CBM_DIAGNOSTICS=1auto_index=falseauto_watch=falseI will attach the diagnostic trajectory if the process exceeds the requested cap after all clients are restarted. No proprietary source or repository contents are included here.
rarepops commentedon Aug 24, 2026
Follow-up under the new containment profile (
CBM_MEM_BUDGET_MB=4096,CBM_WORKERS=1, diagnostics enabled), with no indexing and auto-index/watch disabled:I exercised 17 real MCP calls through one persistent v0.10.8 client against existing graphs, including:
list_projects,index_statussearch_graph(BM25 and semantic)search_codewith full sourceget_code_snippet,trace_pathcheck_index_coverageget_architectureon 13k-node and 138k-node projectsquery_graphThe largest operation was
MATCH (a)-[r:CALLS]->(b) RETURN count(r)on a 138,279-node / 462,750-edge graph. It peaked at about 992 MB RSS / 955 MB committed, then returned to about 17 MB RSS / 40 MB committed. Four identical sequential runs had the same peak and no rising settled baseline.Experiment window:
This does not reproduce a read-only query leak under sequential single-client use. It further narrows the prior 16-25.8 GB Windows events to indexing/worker activity (or a distinct multi-client concurrency path), rather than ordinary metadata/search/trace/Cypher use. Two calls submitted concurrently through one stdio client were serialized, so independent-client query concurrency remains untested.
experticket-admin commentedon Sep 3, 2026
Fresh v0.10.8 evidence from Windows x64 confirms that the supervisor's per-worker budget is not an enforcement boundary.
With
CBM_MEM_BUDGET_MB=12288andCBM_WORKERS=1, the daemon logged:Despite the reported 3 GiB worker cap, three successive indexing workers reached approximately 39.0, 39.0, and 40.3 GiB private bytes. At the system level, available memory fell to 351 MiB and committed memory reached 96.3 GiB before the indexing processes exited. No repository contents or private paths are included in these measurements.
The Windows subprocess supervisor currently creates a Job Object with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, but does not set a Job memory limit. The worker receives the budget through argv for internal accounting only, so Windows commit remains unconstrained if that accounting is exceeded.PR #2030 adds
JOB_OBJECT_LIMIT_JOB_MEMORYusing the supervisor-calculated per-worker budget and includes a native Windows regression probe. It is intentionally a host-safety boundary, not a claim that the underlying indexing growth itself is fixed.DeusData commentedon Sep 3, 2026
Thank you @experticket-admin for the fresh v0.10.8 measurements and for separating host containment from the underlying indexing growth.
A reported 3 GiB worker budget alongside roughly 39 to 40 GiB private-byte peaks is strong evidence that the current Windows supervisor budget is accounting rather than an OS enforcement boundary. PR #2030 is now routed as a high-priority Windows stability fix.
Because it changes Job Object limits and failure behavior for worker process trees, we need more time to review it carefully. No additional measurements are requested from you right now. Thank you for adding a native Windows probe instead of treating the limit as self-evident.
Merge pull request #2112 from DeusData/fix/decision-a-memory-budget-f…
DeusData commentedon Sep 9, 2026
Fixed on main by #2112 (merge 1d66538). An over-budget index attempt now fails the whole attempt with a named error (CBM_PIPELINE_ABORT_OVER_BUDGET) after one back-pressure-futility confirmation cycle, instead of the old open-ended soft overshoot that let the kernel OOM-kill the worker. Staging is discarded through the existing rc≠0 path, so the previously serving index is kept byte-identical and no partial graph is published; the worker exits cleanly with a named reason (never a kill, so the supervisor no longer blames innocent files). The daemon also slices the worker memory budget by the number of active jobs. Thanks for the report — closing as fixed.
fix(pipeline): fail an over-budget index attempt whole instead of sof…
fix(mcp): name the cause when an index attempt stops before publication
fix(daemon): slice the worker memory budget by active jobs, not by th…
fix(pipeline): fail an over-budget index attempt whole instead of sof…
fix(mcp): name the cause when an index attempt stops before publication
fix(daemon): slice the worker memory budget by active jobs, not by th…