Skip to content

Threads: nursery/generational GC and context lifecycle performance #16

Description

@chrisbbreuer

Parent: #1

Goal

Make the GC-backed threaded runtime competitive for allocation-heavy and create/destroy-heavy embedders without weakening no-GIL correctness.

Current baseline

  • GC cells use size-class slabs with lazy bump allocation, freelist reuse, per-size-class fast-path locks, tail-slab trimming, exact bucket counters, and slab-owned bulk teardown.
  • New cells enter a non-moving, one-cycle nursery. Demand-driven quiescent minor collection traces young roots plus remembered old owners, reclaims dead young cells, and immediately tenures survivors.
  • Owner-aware strong barriers cover Object, Environment, Promise, collection, prototype, generator-request, and native synchronization side-record stores. Broad maybe-managed root/barrier inputs use exact live-payload membership instead of candidate-header peeks, with zig-gc's payload index keeping that safety off the O(live-cells) path. Weak-container barriers preserve WeakRef, WeakMap/WeakSet, and FinalizationRegistry semantics. Mutable type-erased side-cell kinds are conservatively rescanned.
  • Remembered-set allocation failure falls back to the existing precise full collector. Explicit collectGarbage() remains full-heap; no-GIL mid-script collection remains the abort-safe full concurrent protocol.
  • gc-profile separates lifecycle, allocation, backing, churn, finalizer, and nursery attribution. Focused cases are available with -Dgc-profile-case='<exact table name>' so nursery and lifecycle rows can be checked without paying for the full profile matrix.
  • Nursery rows now include object-only and array/object allocation shapes, young/reclaimed/promoted counts and bytes, survival/reclamation percentages, the computed next nursery threshold, and repeated-cycle threshold drift. Sizing policy can be judged from pause, survival, reclamation, allocation shape, and threshold trajectory together.
  • zig-gc records last-minor young/reclaimed/promoted byte totals, uses gradual threshold decay after low-survival cycles, caps upward threshold growth to the observed young batch size, trims oversized empty collector scratch after post-spike collections, and serializes allocation metadata for single-mutator concurrent marking without opting that mode into the multi-mutator parallel-GC protocol.
  • Long-lived context reuse remains materially cheaper than create-per-task use; the supported guidance is a bounded pool per isolation domain, one task at a time per context unless the host intentionally shares a realm, and quiescent collectGarbage() at measured task boundaries.

Milestones

  • Design and implement a nursery/young-generation policy with remembered-set coverage.
  • Add promotion/tenuring and full-heap fallback invariants.
  • Prove write-barrier coverage for old-to-young references under no-GIL mutation.
  • Reduce intrinsic context bootstrap and teardown work further, or document a supported pooling/reuse pattern with measured bounds.
  • Add allocation/collection pause, promotion, byte-pressure, survival-rate, allocation-shape, and next-threshold metrics to gc-profile.
  • Add focused GC profile filters so small nursery/lifecycle checks do not require the full matrix.
  • Tune first-pass nursery threshold policy: gradual decay after low-survival cycles and capped growth after high-survival fixed-size bursts.
  • Trim oversized empty collector scratch so pooled contexts do not retain arbitrary one-off spike capacity.
  • Add focused unit, TSan, concurrent-GC regression, corpus, weak/finalization, and churn/fuzzer coverage for the policy.

Remaining work

  • Tune nursery sizing and pause/throughput policy across more workload shapes using the focused profile rows.
  • Decide from measurements whether multi-age, copying/moving, or parallel minor collection earns its complexity.
  • Continue Context lifecycle reductions where profile evidence shows a bottleneck; keep the pooling guidance current as those costs move.
  • Keep old-to-young barrier coverage, exact maybe-managed safety, scratch-lifetime behavior, and weak semantics regression-gated as mutable engine state evolves.

Acceptance criteria

  • No regression in full unit, PR-249, suppression-witness, test262-parallel, or concurrent fuzzer gates.
  • Allocation and lifecycle changes have before/after profile evidence.
  • The implementation docs distinguish slab allocation, nursery policy, full/concurrent collection, and embedder lifecycle guidance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions