gcry v0.5.0
gcry
A garbage collector written in Crystal, intended as an alternative to bdwgc (Boehm GC).
Ships as a shard: reopen Crystal’s GC module under -Dgc_none — no Crystal compiler or stdlib patch required.
Status: v0.5 — STW majors, pause p50/p99, richer
prof_stats, safe opt-in chunk release. Phases 0–8.
- DESIGN.md — architecture, frozen API, roadmap
- docs/INTEGRATION.md — Crystal
GC/ fiber notes- docs/HARDENING.md — stress, tuning, false retention
- docs/POLICY.md — OOM, fork, signal safety
- docs/COMPARISON.md — bdwgc comparison checklist
- docs/PERF.md — % of Boehm (Kemal wrk)
- CHANGELOG.md — notable changes
Why
Crystal ships with Boehm today (boehm backend) and also supports gc_none. gcry replaces the gc_none stubs at require-time with a conservative mark–sweep collector implemented in Crystal — no Crystal compiler/stdlib patch required.
Goals
- Match Crystal’s
GCAPI (malloc,malloc_atomic,collect, fiber roots, finalizers, stats, …) - Conservative stop-the-world mark–sweep on Linux x86_64 under Crystal 1.21+
Fiber::ExecutionContext(parallelism 1) - Nursery + incremental mark slices (no write barriers / no parallel contexts yet)
- Allocation-free collector core (no managed-heap allocations during collect)
- Activate via
require "gcry"+-Dgc_none
Details, non-goals, and phased roadmap live in DESIGN.md.
Supported platforms (v0.5)
| OS / arch | Linux x86_64 (primary); aarch64 cross-compile smoke in CI |
| Crystal | >= 1.21.0 |
| Runtime | Default Fiber::ExecutionContext (parallelism 1) — not parallel contexts / deprecated -Dpreview_mt |
| Fork / signals | See docs/POLICY.md |
Requirements
- Crystal
>= 1.21.0
Installation
Add the dependency to your shard.yml:
dependencies:
gcry:
github: sdogruyol/gcry
shards install
Usage
Require gcry early when building with the null GC, then compile with -Dgc_none:
{% if flag?(:gc_none) %}
require "gcry"
{% end %}
puts "hello"
crystal build -Dgc_none app.cr -o app
./app
Without -Dgc_none, Crystal links Boehm; do not install gcry as the process GC in that mode.
There is no separate application-level allocator API for normal programs: allocations go through Crystal’s runtime (GC.malloc / language allocations). The shard overrides GC underneath.
Tuning
| Variable | Effect |
|---|---|
GCRY_THRESHOLD |
Bytes since last major before auto-collect (process default 64 MiB) |
GCRY_DISABLE_AUTO=1 |
Disable major auto-collect |
GCRY_NURSERY |
Opt-in nursery; young bytes before minor (default off in process GC) |
GCRY_DISABLE_NURSERY=1 |
Keep nursery disabled (process default) |
GCRY_DISABLE_INCREMENTAL=1 |
Full STW major on threshold (process default since v0.4) |
GCRY_INCREMENTAL=1 |
Experimental sliced auto-majors (unsafe without write barriers) |
GCRY_INCREMENTAL_WORK |
Mark work units per collect_a_little slice (default 1024) |
GCRY_RELEASE_CHUNKS=1 |
Munmap fully free size-class chunks after major (opt-in) |
GCRY_KEEP_CHUNKS=1 |
Force empty chunks retained (overrides release) |
More detail: docs/HARDENING.md, docs/POLICY.md. Pause times: Gcry.pause_stats (last_ns / p50_ns / p99_ns / max_ns / total_ns / count).
Performance (v0.5)
Canonical: docs/PERF.md (% of Boehm, same host).
| Path | gcry / Boehm |
|---|---|
/ |
~92% |
/json |
~82% |
/json + GCRY_RELEASE_CHUNKS=1 |
~49% |
Library-heap microbench: make bench → ./bin/churn. Process-GC: make bench-kemal-wrk.
Development
make spec # unit specs under Boehm
make samples # build -Dgc_none samples into bin/
make bench # library-heap churn bench
make bench-kemal-wrk # Kemal + wrk on / and /json (-c 100 -d 30)
make format-check
Or directly:
crystal spec
crystal build -Dgc_none samples/stress.cr -o bin/stress && ./bin/stress 300
crystal build bench/churn.cr -o bin/churn && ./bin/churn 2000
cd bench/kemal && shards install
crystal build -Dgc_none --release src/server.cr -o ../../bin/kemal-gcry
PORT=3001 ../../bin/kemal-gcry
# then: wrk -c 100 -d 30 http://127.0.0.1:3001/
# wrk -c 100 -d 30 http://127.0.0.1:3001/json
Heap unit tests run under the default (Boehm) GC while Gcry::* is exercised as a standalone allocator. Process-GC samples need -Dgc_none.
Roadmap phases 0–7 are complete — see DESIGN.md. Policies and comparison notes: docs/POLICY.md, docs/COMPARISON.md.
Contributing
- Fork the repo
- Create your branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push the branch (
git push origin my-new-feature) - Open a Pull Request
Please keep collector hot paths free of managed-heap allocations, and prefer small, testable modules (heap, mark, sweep, roots).
License
MIT — see LICENSE.
Contributors
- Serdar Dogruyol — creator and maintainer
gcry
- 6
- 0
- 0
- 0
- 0
- 13 minutes ago
- July 23, 2026
MIT License
Thu, 23 Jul 2026 13:50:32 GMT