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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions