v0.1.3 — string garbage collection
Sprout v0.1.3 closes the last big memory-model gap: heap strings are now garbage-collected too.
The conservative mark-sweep GC (v0.1.0) already reclaimed lists, maps, environments, and closures — but strings still leaked (a deliberate, safe first step). This was the planned next slice, and it's done: long-running programs now stay bounded for real.
How it works (no language change — the freeze holds; this is invisible)
- Every
Value's text is now a GC-owned copy:vstr()copies its argument into a newGC_STRand never takes ownership, so it can never free borrowed/AST memory;vstr_take()copies a malloc-owned buffer and frees the original. gc_push_valuemarks strings; the sweep frees an unmarkedGC_STRlike any leaf object.- Strings owned by map keys, environment names, and the module tables stay plain
mallocon purpose — they live where the conservative stack scan never reaches, so the GC must not touch them.
Validated
- Full suite + 12 examples pass normally and under
SPROUT_GC_STRESS=1(collect on every statement — any wrongly-freed live string corrupts a result). - A new string torture test (concat loops, strings as map keys + values, a closure capturing a string, heavy
upper/split/join/replacechurn) stays intact under stress. - 3,000,000 throwaway strings now peak at ~37 MB instead of leaking to hundreds.
- AddressSanitizer + GC-stress green in CI on Linux; an adversarial memory-safety review (ownership, root-completeness, error-unwinding) found nothing.
Also
- Corrected stale docs: the README and
gc-design.mdnow reflect a fully collected runtime, and the "no closures yet" note is fixed (closures shipped in v0.0.24).
Windows installer: SproutSetup.exe below.