A rough sketch of the process is that we first run GC normally, then if something remains, that is force-recycled.
No. We don't run GC at last.
diff --git a/gc.c b/gc.c
index 19ddf9bf20..d9f83dfaf8 100644
--- a/gc.c
+++ b/gc.c
@@ -7183,6 +7183,7 @@ gc_enter(rb_objspace_t *objspace, const char *event)
mjit_gc_start_hook();
during_gc = TRUE;
+ fprintf(stderr, "gc_enter: %s [%s]\n", event, gc_current_status(objspace));
gc_report(1, objspace, "gc_enter: %s [%s]\n", event, gc_current_status(objspace));
gc_record(objspace, 0, event);
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_ENTER, 0); /* TODO: which parameter should be passed? */
```
This patch shows GC events every time. Output:
```
$ ./miniruby -e 'a=[];10000.times{a<<[]}; p "to be exit"'
gc_enter: gc_start [N]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: sweep_continue [SL]
gc_enter: gc_start [N]
gc_enter: sweep_continue [SL]
"to be exit"
gc_enter: rb_objspace_call_finalizer [N]
```
`rb_objspace_call_finalizer` run finalizers for all objects (don't collect, but run special finalize functions).