If you survive 3 collections, you become old • Because most objects die young, you perform (fast) minor GC frequently and (slower) stop- the-world major GC rarely • The RGenGC algorithm (Koichi Sasada, EuRuKo)
major GC (the RincGC algorithm) • Tricolor marking: white (unmarked), gray (marked, but may refer to white objects), and black (marked, without references to white objects)
write barrier protected and write barrier unprotected objects • Pause time is relative to the number of living write barrier unprotected objects • Most objects (String, Array, Hash, or user-defined POROs) are write barrier protected objects, so the pause time for unprotected objects is acceptable
RValues • When there are no more free RValues, Ruby 1.9 sets FL_MARK on all active Ruby objects (marks)... • ...then relinks inactive objects (sweeps) into a single linked list (the “free list”)
the new child process shares all memory with the parent • Copies are only made when changes are written, but marking objects as live on the objects themselves forces a write • Ruby 1.9.3 GC subverts native copy on write
beginning of each heap that contains a pointer to a bitmap representing the state of each object (1 == marked, 0 == unmarked) • The GC mark phase no longer modifies objects, allowing child processes to appropriately leverage copy on write
forking itself N times (which is not a Bad Thing™) • Without copy on write, each worker spends time and memory making copies of objects that are marked by the GC but are otherwise identical • As N increases, the problem gets worse
GC runs and took approximately 4.4 seconds • Loading the app in 2.0 invoked 66 GC runs and took approximately 3.0 seconds • In this case, 1.9.3 spent 47% more time collecting garbage
a full GC run; defaults to 8MB) • RUBY_HEAP_MIN_SLOTS (controls slots per heap, defaults to 10_000) • RUBY_HEAP_SLOTS_GROWTH_FACTOR (controls heap allocation rate, defaults to 1.8x)