Skip to content

Latest commit

 

History

History
88 lines (64 loc) · 3.58 KB

API.md

File metadata and controls

88 lines (64 loc) · 3.58 KB

gcry API surface (shard)

Integration

# shard.yml
dependencies:
  gcry:
    github: sdogruyol/gcry

# app.cr
{% if flag?(:gc_none) %}
  require "gcry"
{% end %}
crystal build -Dgc_none app.cr

Under -Dgc_none, require "gcry" reopens Crystal’s GC module. Everyday code keeps using String / Array — no separate malloc API for app objects.

Module Gcry

API Role
Gcry::VERSION Shard version string
Gcry.default_heap Process / default Heap
Gcry.malloc / malloc_atomic / realloc / free Library-heap helpers (tests)
Gcry.usable_size(ptr) Usable size of the live block containing ptr (base or interior), at least the requested size (Boehm GC_size); 0 when no live gcry block contains it
Gcry.collect / minor_collect / collect_a_little Manual collection
Gcry.pause_stats STW pause ring (last / p50 / p99 / max / count)
Gcry.metrics Extended counters (collections, RSS-ish bytes, blacklist, …)
Gcry.prometheus_text Prometheus exposition format
Gcry::Observability.json_stats JSON snapshot for /gc-stats
Gcry.dump_heap(io) Live-object NDJSON dump (debug; large heaps may take seconds)
Gcry.dump_heap_addresses / heap_dump_gone / heap_dump_new Address-set dump + leak diff helpers
Gcry::Trace NDJSON event log (GCRY_TRACE=1); writes via LibC.write (no JSON/OpenSSL in GC path)

Class Gcry::Heap

Conservative mark–sweep allocator used as the process GC or as a private heap under Boehm in specs.

Notable knobs (also via GCRY_* env on process GC): gc_threshold, nursery_enabled, incremental_auto, release_empty_chunks, type_id_gate, blacklist_enabled, tlab_enabled, stop_the_world.

Nursery (generational)

The nursery is a young-object space (size-class chunks tagged NURSERY). Allocations go there when nursery_enabled is true. A minor collection walks roots + old→young edges (via page-dirty barrier on Linux, full old scan on Darwin) and promotes survivors to old-space.

Process GC defaults:

  • Linux + Darwin: nursery disabled (soft-dirty false negatives on HTTP made default-on unsafe). Opt in with GCRY_NURSERY=1 (adaptive threshold still applies when enabled).
  • Soft-dirty / mprotect barrier backends remain Linux-only; Darwin nursery uses full old→young scan if enabled.

Adaptive threshold

When adaptive_nursery is true (default), the threshold adjusts after each minor based on the moving-average survival rate (last 10 minors):

Survival rate Action
> 50% target Threshold grows 25% (collect less often)
< 25% Threshold shrinks 25% (collect sooner, limit survivor pressure)

Clamped to [64 KiB, 8 MiB]. Disable with GCRY_DISABLE_ADAPTIVE_NURSERY=1 or set heap.adaptive_nursery = false.

Monitoring

/gc-stats exposes nursery_survival_bytes, nursery_alloc_before_minor, nursery_survival_rate_pct, adaptive_nursery. Prometheus exposes gcry_nursery_* gauges.

Env knobs

See README.md Tuning table and HARDENING.md.

HTTP example

{% if flag?(:gc_none) %}
  get "/metrics" do |env|
    env.response.content_type = "text/plain; version=0.0.4"
    Gcry.prometheus_text
  end

  get "/gc-stats" do |env|
    env.response.content_type = "application/json"
    Gcry::Observability.json_stats
  end
{% end %}

Kemal bench and acikturkiye dogfood the same helpers: GET /gc-stats → Gcry::Observability.json_stats, GET /metrics → Gcry.prometheus_text (under -Dgc_none).