Problem
Automatic collections in compiled programs are synchronous, unbounded, alloc-point STW cycles because the budgeted (incremental) machinery is structurally unreachable:
- ~50 of ~57 registered root scanners have no budgeted step form, and any unbudgeted scanner blocks the sliced stepper: predicate
gc/roots.rs:286-307, registrations gc/mod.rs:289-454.
- The alloc-point direct arm (
gc/policy.rs:1232-1284) forces the conservative scan (:1254), which makes the copying fast path ineligible (gc/copying.rs:769-774) — so the collection lands in GcCycleState::new_minor_fallback(...).run_to_completion() with an unbounded budget (gc/cycle.rs:1002-1009).
PERRY_GC_INCREMENTAL=1 exists but is off by default and has a runaway hole: mutator assists only advance 4 phases (gc/cycle.rs:47-55, gc/policy.rs:1772-1778), so a compute loop that never reaches the event pump parks a cycle at the sweep boundary indefinitely with the incremental-mark barrier still enabled (gc/cycle.rs:1041-1044) → unbounded RSS.
Proposed fix (staged)
- Convert the ~15 highest-traffic scanners to budgeted form (runtime handles, promise, timer, class/symbol tables already are; object caches, descriptor tables, closure caches, error props, fs/process tables are not).
- Let mutator assists drive all resumable phases (sweep is already sliced), or add a debt cap that escalates to a synchronous finish —
GcDebtSnapshot (gc/telemetry.rs:446-468) already measures exactly this but is telemetry-only.
- Graduate
PERRY_GC_INCREMENTAL to default-on once 1+2 land.
- Route alloc-point trigger crossings to the pump-boundary moving minor via the existing deferral flag (
gc/policy.rs:1246-1251) by default once loop-poll coverage lands.
Context
2026-07-09 GC audit. Successor to #6083, whose closure shipped the trigger re-arm fix and the off-by-default incremental mode but left the default path fully STW.
Problem
Automatic collections in compiled programs are synchronous, unbounded, alloc-point STW cycles because the budgeted (incremental) machinery is structurally unreachable:
gc/roots.rs:286-307, registrationsgc/mod.rs:289-454.gc/policy.rs:1232-1284) forces the conservative scan (:1254), which makes the copying fast path ineligible (gc/copying.rs:769-774) — so the collection lands inGcCycleState::new_minor_fallback(...).run_to_completion()with an unbounded budget (gc/cycle.rs:1002-1009).PERRY_GC_INCREMENTAL=1exists but is off by default and has a runaway hole: mutator assists only advance 4 phases (gc/cycle.rs:47-55,gc/policy.rs:1772-1778), so a compute loop that never reaches the event pump parks a cycle at the sweep boundary indefinitely with the incremental-mark barrier still enabled (gc/cycle.rs:1041-1044) → unbounded RSS.Proposed fix (staged)
GcDebtSnapshot(gc/telemetry.rs:446-468) already measures exactly this but is telemetry-only.PERRY_GC_INCREMENTALto default-on once 1+2 land.gc/policy.rs:1246-1251) by default once loop-poll coverage lands.Context
2026-07-09 GC audit. Successor to #6083, whose closure shipped the trigger re-arm fix and the off-by-default incremental mode but left the default path fully STW.