summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2023-11-23 14:53:53 -0500
committerPeter Zhu <peter@peterzhu.ca>2023-11-24 09:28:34 -0500
commit99e1f7b60717bc5ca3b160f10f4a8fe1521cba7c (patch)
tree2d1d2d1a4bdef75d3e8ce3d7508aa6fa96962c89 /gc.c
parent406dafbb347cb81f6d256d18ac9fd2908a9cb8ef (diff)
Abort GC on shutdown
On large Ruby applications, shutdown may be slow if a major GC has just started because rb_objspace_call_finalizer completes the GC. This commit adds gc_abort which discards the mark stack if during incremental marking and stops sweeping if during lazy sweeping.
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/gc.c b/gc.c
index 3f992604b2..d1c5efb780 100644
--- a/gc.c
+++ b/gc.c
@@ -1302,7 +1302,7 @@ total_freed_objects(rb_objspace_t *objspace)
}
#define gc_mode(objspace) gc_mode_verify((enum gc_mode)(objspace)->flags.mode)
-#define gc_mode_set(objspace, mode) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(mode))
+#define gc_mode_set(objspace, m) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(m))
#define is_marking(objspace) (gc_mode(objspace) == gc_mode_marking)
#define is_sweeping(objspace) (gc_mode(objspace) == gc_mode_sweeping)
@@ -4511,6 +4511,36 @@ gc_finalize_deferred_register(rb_objspace_t *objspace)
}
}
+static int pop_mark_stack(mark_stack_t *stack, VALUE *data);
+
+static void
+gc_abort(rb_objspace_t *objspace)
+{
+ if (is_incremental_marking(objspace)) {
+ /* Remove all objects from the mark stack. */
+ VALUE obj;
+ while (pop_mark_stack(&objspace->mark_stack, &obj));
+
+ objspace->flags.during_incremental_marking = FALSE;
+ }
+
+ if (is_lazy_sweeping(objspace)) {
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ heap->sweeping_page = NULL;
+ struct heap_page *page = NULL;
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ page->flags.before_sweep = false;
+ }
+ }
+ }
+
+ gc_mode_set(objspace, gc_mode_none);
+}
+
struct force_finalize_list {
VALUE obj;
VALUE table;
@@ -4539,15 +4569,12 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
#if RGENGC_CHECK_MODE >= 2
gc_verify_internal_consistency(objspace);
#endif
- gc_rest(objspace);
-
if (ATOMIC_EXCHANGE(finalizing, 1)) return;
/* run finalizers */
finalize_deferred(objspace);
GC_ASSERT(heap_pages_deferred_final == 0);
- gc_rest(objspace);
/* prohibit incremental GC */
objspace->flags.dont_incremental = 1;
@@ -4565,6 +4592,9 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
}
}
+ /* Abort incremental marking and lazy sweeping to speed up shutdown. */
+ gc_abort(objspace);
+
/* prohibit GC because force T_DATA finalizers can break an object graph consistency */
dont_gc_on();