v0.15.0
Correctness release: process-STW × TLAB freelist UAF class fixed and CI-gated;
process-STW MT property harness; acikturkiye Linux re-cut measured; shard RSS
dead-end defaults documented. Supported path remains EC parallelism 1,
GCRY_TLAB off (Parallel+TLAB stays experimental).
Performance
- Linux Kemal (same-host median-of-3,
wrk -c 100 -d 30, scrub on):/json~86% of Boehm @ ~0.77× post-GC RSS;/~86% @ ~0.76×. Sessionbench/log/linux/2026-07-29-151144/(bebedae). Collector defaults unchanged vs 0.14 — thr within host noise of the v0.14 ~89% cut. See docs/PERF.md (Linux). - acikturkiye Linux re-cut (measured):
/api/v1/~90% of Boehm thr @ ~2.54× post-GC RSS (median-of-3,wrk -c 100 -d 30, scrub on). Sessionbench/log/linux/2026-07-29-112202/(9decd01). Replaces the v0.14.0 ~93% / ~2.65× estimate. See docs/ACIKTURKIYE.md. - Shard RSS A/B (defaults unchanged): same-host cuts rejected as defaults — Linux HOLED
GCRY_PAGE_DONTNEED, process-default curatedHTTP::Headers::KeyHash layout, collect-time mutatorclear_stack, Linux 1 MiB large-cache floor. Keep fiber scrub, Linux 4 MiB large-cache, HOLED opt-in; Headers layout stays app-side /GCRY_AUTO_LAYOUTS. See docs/ACIKTURKIYE.md “Don’t bother”.
Fixed
- Explicit-root list × process STW race:
add_root/delete_rootcould run concurrently withstop_world, freezing a mutator mid-list splice so@roots.eachwalked a freed/next-corruptRootNode(SEGV atrun_collectionduringstw_mt_property_test). Serialize mutations with@roots_lockacquired before STW; collector may mutate without the lock while@world_stopped. - Parked-fiber scrub on thinly mapped stacks: Cap wipe to the same 512 B fiber path as
clear_stackand zero only readable pages viaRoots.clear_range_safe(defense in depth; Crystal fiber stacks grow on demand). - TLAB + Parallel under process STW: mid-
tlab_alloc_smallSTW could leave FREE freelist nodes only reachable from mutator stacks; mark ignored FREE, then empty-chunk release munmapped them (andunlink_freelist_rangecould coerce USED→FREE). Fix: claim FREE stack/thread roots when TLAB+STW (clear FREE but keepnext_freeso scrub can walk the chain —set_usedwas severing freelists → OOM), freelist scrub after flush/mark (TLAB-only), flush only FREE nodes, TLAB epoch + detach-before-claim (no dual-alloc after flush), no nestedcollectunder@alloc_lock(deadlock), unlock-and-collect retry on refill miss, steal stranded TLAB freelists, skip nilThread#current_fiberunder Parallel. CI gatesstw_mt_property_test --tlab --workers=2,4.
Added
- Process-GC STW MT property harness:
bench/stw_mt_property_test.cr(-Dgc_none) runs Parallel allocator workers while the default EC pins roots (ACK handshake) andGC.collects under real STW. Closes the gap left by library-heapmt_property_test(stop_the_world=false). CI gates--workers=2,4and--tlab --workers=2,4. (make stw-mt-property-test)
Changed
- Docs / knobs: Linux HOLED page release documented as opt-in (post-STW; not “STW-heavy”). Large-cache defaults clarified (Linux process 4 MiB, Darwin 1 MiB). Darwin
GCRY_DISABLE_PAGE_RELEASE=1/GCRY_DISABLE_MADVISE=1explicitly clearmadvise_free_pages.