What’s wrong with Ruby?
• not as fast as some languages
Slide 10
Slide 10 text
What’s wrong with Ruby?
• not as fast as some languages
• concurrency is a swear word
Slide 11
Slide 11 text
What’s wrong with Ruby?
• not as fast as some languages
• concurrency is a swear word
• garbage collector is garbage
Slide 12
Slide 12 text
Garbage Collector is garbage
Y?
Slide 13
Slide 13 text
Lifetime of an object
Slide 14
Slide 14 text
Lifetime of an object
Object.new
Slide 15
Slide 15 text
Lifetime of an object
Object.new
rb_class_new_instance()
Slide 16
Slide 16 text
Lifetime of an object
Object.new
rb_obj_alloc() 㱺 .allocate
rb_obj_call_init() 㱺 #initialize
Slide 17
Slide 17 text
Lifetime of an object
.allocate
rb_newobj() /* gc.c */
Slide 18
Slide 18 text
Lifetime of an object
rb_newobj():
1. try to bite from freelist
Slide 19
Slide 19 text
Lifetime of an object
rb_newobj():
1. try to bite from freelist
2. if freelist is empty invoke GC
Slide 20
Slide 20 text
Lifetime of an object
rb_newobj():
1. try to bite from freelist
(except for basic types)
2. if freelist is empty invoke GC
Slide 21
Slide 21 text
Lifetime of an object
rb_newobj():
1. try to bite from freelist
(except for basic types)
2. if freelist is empty invoke GC
(everything lives on a heap)
No such thing to reveal
where an object was allocated
;(
Showing code location
Slide 55
Slide 55 text
No such thing to reveal
where an object was allocated
But we can hack it up!
Showing code location
Slide 56
Slide 56 text
class M
attr_reader :allocated_at
def initialize
@allocated_at = caller.first
end
end
m = M.new
puts m.allocated_at.inspect
Showing code location
Slide 57
Slide 57 text
class BasicObject
attr_reader :allocated_at
def initialize_with_allocated_at(*options)
unless @allocated_at
@allocated_at = caller.first
return initialize_without_allocated_at(*options)
end
end
def self.enable_allocated_at
self.send :alias_method, :initialize_without_allocated_at, :initialize
self.send :alias_method, :initialize, :initialize_with_allocated_at
end
end
Showing code location
Slide 58
Slide 58 text
# Enabling allocation tracking on every object
ObjectSpace.each_object(Class) do |klass|
klass.enable_allocated_at
end
# Building a huge allocation map of all the objects in the system
class Object
def allocation_map
ObjectSpace.each_object.reduce({}) { |hash, object|
hash[object.allocated_at] ||= []
hash[object.allocated_at] << object if object.respond_to?(:allocated_at)
hash
}
end
end
Showing code location
Slide 59
Slide 59 text
Ruby 2.0
Slide 60
Slide 60 text
• Enumerable::Lazy
[1, 2, 3].lazy.map { ... }.select
bypasses intermediate arrays,
albeit is currently very slow
Ruby 2.0
Slide 61
Slide 61 text
• Bitmap marking
helps to avoid pre-2.0 problem
where fork()-CoW is useless
because of GC marks
Ruby 2.0
Slide 62
Slide 62 text
• caller_locations versus caller
is orders of magnitude faster
and thus can replace caller
in the original allocations_map
Ruby 2.0
Slide 63
Slide 63 text
• immediate Floats
only on 64-bit systems,
speeds up floating point
calculations
Ruby 2.0
Slide 64
Slide 64 text
is coming in December 2013
Ruby 2.1
Slide 65
Slide 65 text
is coming in December 2013
with generational GC:
https://bugs.ruby-lang.org/
issues/8339
Ruby 2.1
Slide 66
Slide 66 text
collects younger objects
more often
Generational GC