Circular Object Graph

a = [ nil ]; b = [ a ]; c = [ b ]
a[0] = c; b = c = nil;

Circular Object Graph

Ref Counts

Initial Object Graph

x = [ 0, 1, "two", "three", :four, 3.14159, 123456781234567812345678 ]
y = { :a => 1, :b => "bee" }
x << y

Initial Object Graph

Mark and Sweep

Mark

  • Starting with Roots,
  • Mark each referenced object, if unmarked,
  • Recursively.

Sweep

  • For all objects in memory,
  • Free unmarked objects,
  • Unmark marked objects.

Roots

  • Global Namespace : Kernel, Object
  • Global Variables and CONSTANTS : $:, ARGV
  • Local Variables : binding, caller
  • self, &block
  • Internals: rb_global_variable(), VALUEs on C stack.

Remove reference to “three”

x[3] = nil

Remove reference to “three” : Before

Remove reference to “three” : After

GC: Mark roots

GC: Mark Array@0

GC: Mark String@1

GC: Mark Float@3

GC: Mark Bignum@4

GC: Mark Hash@5

GC: Mark String@6

GC: Before Sweep

GC: Sweep Array@0 : unmark

GC: Sweep String@1 : unmark

GC: Sweep String@2 : free

GC: Sweep Float@3 : unmark

GC: Sweep Bignum@4 : unmark

GC: Sweep Hash@5 : unmark

GC: Sweep String@6 : unmark

GC: After Sweep (freed 1)

Remove References to Hash

y = nil

Remove References to Hash : Before

Remove References to Hash : After

Remove References to Hash

x[-1] = nil

Remove References to Hash

GC: Mark roots

GC: Mark Array@0

GC: Mark String@1

GC: Mark Float@3

GC: Mark Bignum@4

GC: Before Sweep

GC: Sweep Array@0 : unmark

GC: Sweep String@1 : unmark

GC: Sweep Float@3 : unmark

GC: Sweep Bignum@4 : unmark

GC: Sweep Hash@5 : free

GC: Sweep String@6 : free

GC: After Sweep (freed 2)

3.times { x.pop }

x.pop; x.pop; x.pop

x.pop

x.pop

x.pop

GC: Mark roots

GC: Before Sweep

GC: After Sweep (freed 2)

Mark And Sweep Is Expensive

  • Every reachable object is read.
  • Every mark bit is read and mutated.
  • Even if most of objects are not garbage (Modules, Methods, CONSTANTS, literals).
  • Every freed object is mutated due to free list.

Coding Styles affect GC

  • Every evaluated String, Float, String literal creates a new object.
  • Shared String buffers reduce memory usage, but do not improve GC times.
  • Every Float, Bignum math operation creates a new Object.
  • Use String#<<, not String#+.
  • big_enumerable.clear
  • heavy_object = nil

Mark bits

Copy-On-Write pages after process fork().

  • CRuby <2.0
    • Mark bits are at the head of each object.
    • Faster, but page mutations happen everywhere.
  • REE, CRuby 2.0 (HEAD)
    • Mark bits are stored in external arrays.
    • Slower.

GC: With Mark Bits

GC: Mark Array@0

GC: Mark String@1

JRuby, Rubinius

  • Rubinius has multiple collectors.
  • JVM Collectors are highly-tuned.
  • Some Commercial JVMS have very performant collectors.

Other GC Features

  • Lazy Sweep – already in CRuby.
  • Parallel Sweep – not seen yet.
  • Parallel Mark – prototype presented at RubyConf 2011.
  • N-color marking:
  • Generational – difficult, unlikely.
    • Needs Write Barrier
  • Weak References, Reference Queues

CRuby GC Options

mem_api – http://github.com/kstephens/ruby

Generational GC

  • Youngest objects are likely to be garbage.
  • Younger objects are likely refer to older objects.
  • Older objects are less likely to change or point to younger objects.

Generational GC Is Hard

  • Write Barrier needed to keep track of changes to older or already marked objects.
  • Need to keep track of references from older generations to new generations.
  • CRuby API makes write barrier difficult.
  • Lua GCG is simpler; API nevers expose references; stack operations only.

Mutate older object : Before

x[3] = "three, again!"

Mutate older object : After

x[3] = "three, again!"

Weak Reference

  • Useful for caching.
  • A Weak Reference maintain its reference, iff one or more non-weak references exists.
  • Reference Queues hold dead Weak References for later processing.
  • Soft References release references when under “memory pressure”.

Weak Reference

str = "Another String"
rq = RefQueue.new
wr = rq.add!(WeakRef.new(str))
x << str; str = nil

Weak Reference

Remove Hard Reference

x[-1] = nil

GC: Mark roots

GC: Before Sweep

GC: WeakRef@5 value = nil

GC: RefQueue@6 add!

GC: WeakRefs changed

GC: After Sweep (freed 1)

Weak Reference Support

  • JRuby
    • JVM: Weak References, Soft References, Reference Queues.
  • Rubinius
    • Weak References
  • CRuby

Q&A