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
C emission needs 14+ GB on a 16 GB Mac because JSC sizes its heap from physical RAM #1262
(a ~27k-line program: about 1,800 defs, 24 MB of C)
What happened
On a 16 GB Apple M-series Mac, bend app.bend -o app.c on a ~27k-line program
(about 1,800 defs, 24 MB of C) grows its memory footprint to 14+ GB within
40 seconds. With other work on the machine, the process then compresses and
swaps: one emission ran 94 minutes, reached a 32 GB footprint, and did not
finish. Setting BUN_JSC_forceRAMSize=2147483648 makes the same emission
finish in about 2 minutes at 5–9 GB, with byte-identical C.
Measurements (one emission at a time)
Tree
Bend
Environment
Result
Peak footprint
C size
A (morning)
2.0.31
default
killed at 52 s
>14 GB
–
A
2.0.34
default
killed at 36 s
14.3 GB
–
B (+290 defs)
2.0.31
default
killed at 37 s
14.3 GB
–
B
2.0.31
BUN_JSC_forceRAMSize=4GiB
132 s, ok
9.1 GB
24,060,021
B
2.0.31
BUN_JSC_forceRAMSize=2GiB
124 s, ok
8.6 GB
24,060,021 (identical)
A
2.0.31
forceRAMSize=2GiB
139 s, ok
4.8 GB
22,354,260
B
2.0.34
forceRAMSize=2GiB
126 s, ok
5.8 GB
24,061,798
A larger file in the same program (a test driver that imports every module)
did not finish in 7 minutes on 2.0.31 even with forceRAMSize=2GiB (760 s
system time, memory compression). On 2.0.34 with the same setting it finished
in 385 s.
Observations
The emitter allocates roughly 300–400 MB/s of short-lived garbage. JSC sizes
its heap from physical RAM, so the GC lets the heap grow toward the machine's
size before it collects.
compile_book re-emits all defs until the owner and hot facts reach a
fixed point. On program B it needs at least 5 passes (facts 0 → 4149 →
4351 → 4384 → 4389 → …), at about 25 s per pass.
The TELES memo (tele_unbind2) is keyed by term identity and never cleared
between defs; it holds about 890K entries after file_book. Clearing it did
not reduce peak memory much.
Suggestions
Set a bounded heap for the compiler by default (for example the equivalent
of BUN_JSC_forceRAMSize), or trigger a collection between emission passes.
Emit only the defs whose facts changed on each fixed-point pass, instead of
all defs.
Clear per-def memos such as TELES after each def.
Workaround
export BUN_JSC_forceRAMSize=2147483648
bend app.bend -o app.c
The file
Not small (about 27k lines across many modules).
bend version
bend 2.0.34 (also seen on 2.0.31; darwin-arm64 release binaries)
uname -sm
Darwin arm64 (Apple M-series, 16 GB RAM, 10 cores)
clang --version (the first line)
clang version 21.1.8 (not involved: the memory growth happens during bend -o .c, before any C compile)
Thanks for the measurements. We built a synthetic program of the same size:
27.6k lines, 2,634 defs, 33 modules, 14.4 MB of C. It is made from copies of
the repo's demos, each its own module, imported by one entry. On current main
(dbb3157) -o app.c peaks at 2.2 GB RSS in 6.5 s with 5 fixed-point passes,
and 2.0.34 behaves about the same on it (2.3 GB, 8.3 s). So we can't
reproduce the 14 GB without your program. Our passes cost ~1 s; yours ~25 s.
Some things that went in after 2.0.34 may have fixed it: graph_close became
linear (#1298), TELES now lives per file and stays small (~4k entries here,
it grew to 146k on 2.0.34), and #1196/#1244/#1304/#1362. Could you retry bend app.bend -o app.c on 2.0.37 and post the peak and time? If it still
blows up, a reduced program (or the module that dominates) would help most.
On the heap: BUN_JSC_forceRAMSize still matters. It cuts our peak by 44%
(2.2 → 1.2 GB) for +6% time with identical C. A Bun.gc per pass gives only
~10%.
Activity
Lorenzobattistela commentedon Oct 14, 2026
Thanks for the measurements. We built a synthetic program of the same size:
27.6k lines, 2,634 defs, 33 modules, 14.4 MB of C. It is made from copies of
the repo's demos, each its own module, imported by one entry. On current main
(dbb3157)
-o app.cpeaks at 2.2 GB RSS in 6.5 s with 5 fixed-point passes,and 2.0.34 behaves about the same on it (2.3 GB, 8.3 s). So we can't
reproduce the 14 GB without your program. Our passes cost ~1 s; yours ~25 s.
Some things that went in after 2.0.34 may have fixed it: graph_close became
linear (#1298), TELES now lives per file and stays small (~4k entries here,
it grew to 146k on 2.0.34), and #1196/#1244/#1304/#1362. Could you retry
bend app.bend -o app.con 2.0.37 and post the peak and time? If it stillblows up, a reduced program (or the module that dominates) would help most.
On the heap:
BUN_JSC_forceRAMSizestill matters. It cuts our peak by 44%(2.2 → 1.2 GB) for +6% time with identical C. A
Bun.gcper pass gives only~10%.
Emission allocates 40% less on large files: per-file literal steps, p…