I got auto-compaction to work (the GC automatically compacts after the sweep phase on major collections), but it's not effective. I feel like the explanation is too short for a full blurrrggghhh post, so I'll make a thread
The problem is that Ruby's GC uses incremental sweeping. It sweeps some objects then lets your program run, repeating this process until it's done sweeping. Each "freed" object is returned to the free list, but as your program allocates more stuff it just pops off the list