mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
doc/internal/gc.md: update for debt model and new tuning parameters
Document the debt-based GC trigger model, malloc threshold, step limit, GC.stat, and tuning guide. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
+89
-13
@@ -273,7 +273,7 @@ From Ruby: `GC.generational_mode = true/false`.
|
||||
`mrb_obj_alloc()` is the core allocation function:
|
||||
|
||||
1. If `MRB_GC_STRESS` is defined, run a full GC
|
||||
2. If `gc->live >= gc->threshold`, run `mrb_incremental_gc()`
|
||||
2. Increment `gc->gc_debt`; if positive, run `mrb_incremental_gc()`
|
||||
3. Ensure arena has space (`gc_arena_keep`)
|
||||
4. Pop an object from the freelist of `gc->free_heaps`
|
||||
5. If no free pages, allocate a new page (`add_heap`)
|
||||
@@ -299,18 +299,43 @@ The object's type is set to `MRB_TT_FREE` after freeing.
|
||||
|
||||
## Triggering GC
|
||||
|
||||
### Automatic
|
||||
### Debt Model
|
||||
|
||||
GC runs automatically when `gc->live >= gc->threshold` during
|
||||
object allocation. After each cycle:
|
||||
GC uses a **debt-based feedback model** to balance allocation
|
||||
rate against collection work. The key field is `gc->gc_debt`
|
||||
(signed integer):
|
||||
|
||||
- **Negative** = credit (GC is ahead, no collection needed)
|
||||
- **Zero** = balanced
|
||||
- **Positive** = debt (allocation outpacing collection, GC runs)
|
||||
|
||||
Each object allocation increments `gc_debt` by 1. When debt
|
||||
goes positive, `mrb_incremental_gc()` runs. Each incremental
|
||||
step decrements debt by `GC_STEP_SIZE` (1024), giving credit
|
||||
for many future allocations.
|
||||
|
||||
When a GC cycle completes, credit is calculated from
|
||||
`interval_ratio`:
|
||||
|
||||
```text
|
||||
threshold = (live_after_mark / 100) * interval_ratio
|
||||
credit = (live_after_mark / 100) * interval_ratio - live_after_mark
|
||||
minimum: GC_STEP_SIZE (1024)
|
||||
gc_debt = -credit
|
||||
```
|
||||
|
||||
With default `interval_ratio = 200`, GC triggers when live objects
|
||||
roughly double.
|
||||
With default `interval_ratio = 200` and 1000 live objects:
|
||||
`credit = (1000/100)*200 - 1000 = 1000`, so approximately 1000
|
||||
allocations can occur before the next GC cycle begins.
|
||||
|
||||
### Malloc Pressure
|
||||
|
||||
When `gc->malloc_threshold` is set (non-zero), the GC also
|
||||
tracks bytes allocated through `mrb_realloc_simple()` in
|
||||
`gc->malloc_increase`. When `malloc_increase` exceeds
|
||||
`malloc_threshold`, the counter resets and an incremental GC
|
||||
step runs. This captures memory pressure from large buffers
|
||||
(e.g., long strings) that would otherwise be invisible to the
|
||||
object-count-based debt model.
|
||||
|
||||
### Manual
|
||||
|
||||
@@ -333,6 +358,7 @@ From Ruby: `GC.start`.
|
||||
| `MRB_GC_FIXED_ARENA` | off | Use fixed-size arena |
|
||||
| `MRB_GC_TURN_OFF_GENERATIONAL` | off | Disable generational mode |
|
||||
| `MRB_GC_STRESS` | off | Full GC on every allocation (debug) |
|
||||
| `MRB_GC_STATS` | off | Enable GC statistics counters |
|
||||
| `MRB_USE_MALLOC_TRIM` | off | Call `malloc_trim()` after full GC |
|
||||
|
||||
### Runtime
|
||||
@@ -340,18 +366,68 @@ From Ruby: `GC.start`.
|
||||
From Ruby code:
|
||||
|
||||
```ruby
|
||||
GC.interval_ratio = 200 # threshold = live * ratio / 100
|
||||
GC.step_ratio = 200 # objects per incremental step
|
||||
GC.interval_ratio = 200 # controls debt credit after GC cycle
|
||||
GC.step_ratio = 200 # objects per incremental step
|
||||
GC.step_limit = 0 # 0=unlimited, >0=absolute step cap
|
||||
GC.malloc_threshold = 0 # 0=disabled, >0=bytes to trigger GC
|
||||
GC.generational_mode = true
|
||||
GC.start # force full GC
|
||||
GC.enable # re-enable GC
|
||||
GC.disable # disable GC
|
||||
GC.start # force full GC
|
||||
GC.enable # re-enable GC
|
||||
GC.disable # disable GC
|
||||
```
|
||||
|
||||
### GC Statistics
|
||||
|
||||
`GC.stat` returns a Hash with GC state and statistics:
|
||||
|
||||
```ruby
|
||||
GC.stat
|
||||
# => {
|
||||
# :live => 5432, # live object count
|
||||
# :threshold => 1024, # GC credit (positive=headroom)
|
||||
# :state => 0, # 0=root, 1=marking, 2=sweeping
|
||||
# :generational => true, # generational mode enabled
|
||||
# :full => false, # major GC in progress
|
||||
# :step_limit => 0, # current step limit setting
|
||||
# :malloc_increase => 8192, # malloc bytes since last cycle
|
||||
# :malloc_threshold => 0, # current malloc threshold setting
|
||||
# }
|
||||
```
|
||||
|
||||
With `MRB_GC_STATS` enabled, additional keys are available:
|
||||
|
||||
```ruby
|
||||
# :total => 15, # total GC invocations
|
||||
# :minor => 12, # minor GC count
|
||||
# :major => 3, # major GC count
|
||||
```
|
||||
|
||||
### Tuning Guide
|
||||
|
||||
**`interval_ratio`** (default 200): Controls how many allocations
|
||||
occur between GC cycles. Higher values reduce GC frequency but
|
||||
increase peak memory. The debt credit after each cycle is
|
||||
`(live_after_mark / 100) * interval_ratio - live_after_mark`.
|
||||
|
||||
**`step_ratio`** (default 200): Controls how much work each
|
||||
incremental step performs. Higher values make each step larger,
|
||||
reducing total GC overhead but increasing individual pause times.
|
||||
|
||||
**`step_limit`** (default 0, unlimited): Caps the maximum work
|
||||
per incremental step regardless of `step_ratio`. Useful for
|
||||
real-time applications that need bounded pause times. The
|
||||
effective step size is `min(step_ratio calculation, step_limit)`.
|
||||
|
||||
**`malloc_threshold`** (default 0, disabled): Triggers GC when
|
||||
cumulative `malloc`/`realloc` bytes exceed this threshold. Useful
|
||||
when applications allocate large buffers (strings, data objects)
|
||||
that create memory pressure without proportional object count
|
||||
increase.
|
||||
|
||||
## Source Files
|
||||
|
||||
| File | Contents |
|
||||
| -------------------- | --------------------------------- |
|
||||
| `src/gc.c` | GC implementation (~1400 lines) |
|
||||
| `src/gc.c` | GC implementation |
|
||||
| `include/mruby/gc.h` | `mrb_gc` structure, public GC API |
|
||||
| `include/mruby.h` | Arena save/restore macros |
|
||||
|
||||
Reference in New Issue
Block a user