Skip to content

Interpreter memory pressure can OOM in tight recursive loops before GC reclaims #511

@frostney

Description

@frostney

Problem

Plain interpreted tight recursion can still hit --max-memory before the runtime reclaims unreachable values. PR #497 now narrows its scope to making manual Goccia.gc() safe during active interpreter/bytecode execution, but it does not solve this original memory-pressure case.

Reproduction

printf 'const fib = (n) => n < 2 ? n : fib(n - 1) + fib(n - 2);\nfib(24);\n' | ./build/GocciaScriptLoader --max-memory=500000 --output=json --asi

Current result

On t3code/gc-loop-reclaim at b8b8d9b6, after rebuilding the loader, this exits with RangeError:

Allocation failed: GC heap size exceeds the configured memory limit

Observed GC data from the JSON envelope:

liveBytes: 500128
limitBytes: 500000
collections: 0
collectedObjects: 0
endObjectCount: 9718

Expected behavior

The interpreter should have a safe way to reclaim unreachable temporaries/completed frames in tight function loops before throwing for memory pressure. The script should either complete under this limit or run a safe collection before deciding the heap is genuinely still over MaxBytes.

Findings from PR #497 investigation

  • Broad escaped-reference publication and small-int pinning made the PR too large and regressed full TestRunner runtime from roughly 2s to 10s+.
  • Narrowing Make Goccia.gc safe during active execution #497 restored TestRunner performance while preserving safe manual GC from active interpreter/bytecode execution.
  • Immediate non-escaped call-scope freeing alone is not enough for Fibonacci; transient numeric values still accumulate.
  • Trying to collect directly from TGocciaValue.AfterConstruction when MaxBytes is exceeded is unsafe with the current interpreter, because expression temporaries are not comprehensively rooted.
  • A safer fix likely needs an interpreter safe-point / temporary-root model so memory-pressure collection can run only when current expression temporaries, call frames, return values, and host temps are visible to the marker.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions