Skip to content

fix(string.rep): allocate proportionally to result, not repeat count#376

Merged
davydog187 merged 2 commits into
tv-labs:mainfrom
smn:string-rep-allocation
Jul 3, 2026
Merged

fix(string.rep): allocate proportionally to result, not repeat count#376
davydog187 merged 2 commits into
tv-labs:mainfrom
smn:string-rep-allocation

Conversation

@smn

@smn smn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #373

full disclosure: Claude helped here

`string.rep` built its result with `Enum.map_join(1..n, sep, fn _ -> str
end)`, which materializes an n-element list (plus its iolist) as transient
garbage. For a large repeat count that intermediate is tens of times the
size of the result itself, so producing an otherwise-modest string spikes
the process heap.

This is what issue tv-labs#373 observes: returning a 16 MB string built by
`string.rep` through `Lua.call_function!/3` left ~1 GB of reachable garbage
(call_function returns before the next GC sweeps it), and on a heap-limited
process the spike trips `max_heap_size` and kills it. The same spike occurs
on the `Lua.eval!/2` path; it is just masked there because the surrounding
decode/wrap work triggers a GC before the caller measures.

Build the binary in a single pass with `:binary.copy/2` so allocation is
proportional to the output. The pre-build `Limits.check_string_size!` guard
is unchanged, so oversized requests still raise catchably without
allocating.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvaxgWQcfipbKBaU4KxnuW
@davydog187

Copy link
Copy Markdown
Contributor

Looks great @smn. Will merge once CI passes

Hex 2.5.0 (setup-beam's autoinstalled default on the non-bootstrap
matrix entries) calls :re.import/1 at startup via Hex.Cooldown, and
that function only exists in OTP 28.1+. On OTP 28.0 'mix deps.get'
aborts before fetching anything. Bump all four 28.0 matrix pins to
28.1; the OTP 29.0 entry is unaffected (it pins hex-2.4.2 via curl).
@davydog187 davydog187 merged commit f019515 into tv-labs:main Jul 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lua.call_function!/3 allocates ~50× the payload when a Lua function returns a large string

3 participants