gcry v0.5.0

A garbage collector written in Crystal

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.

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 GC API (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

  1. Fork the repo
  2. Create your branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push the branch (git push origin my-new-feature)
  5. 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

Repository

gcry

Owner
Statistic
  • 6
  • 0
  • 0
  • 0
  • 0
  • 13 minutes ago
  • July 23, 2026
License

MIT License

Links
Synced at

Thu, 23 Jul 2026 13:50:32 GMT

Languages