The Bug that Forced Me to Understand Memory Compaction
summary
A segfault occurs when calling gc.compact on Ruby 2.7 because a C extension keeps a long‑lived Ruby object unmarked so it moves during compaction; Ruby 2.7 pins marked objects during the initial GC pass. The bug is in an unregistered global (rb_bson_registry), fixed by calling rb_gc_register_mark_object to pin it, or by using rb_gc_mark_no_pin plus compaction callbacks and rb_gc_new_location to update pointers; the registration fix stops the crashes and restores correct behavior.
AI-written summary · about
chapters (26)
- 0:00Intro
- 2:31BSON gem
- 4:42Ruby heap
- 5:27Allocating memory
- 6:19Mark and sweep
- 8:25The heap after GC
- 8:46Reality check
- 9:04Memory bloat
- 10:34What I'd learned so far
- 12:28Ruby objects in C
- 14:09Declaring new Ruby types
- 15:33Memory compaction and C extensions
- 17:23Garbage collection and C extensions
- 18:39Mark callbacks
- 19:27Garbage collection with mark callback
- 19:49Marking long-lived objects Extension VALUE greeting
- 21:50Mark and pin
- 23:57Elementary, my dear
- 24:23The suspects
- 24:45The culprit
- 25:32The solution
- 25:43Moving forward
- 26:29rb_gc_mark_no_pin()
- 26:53Compaction callback
- 27:35What I learned
- 28:44Sources








