Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MRI Memory Management

MRI Memory Management

Among the most notable trends in the Ruby community nowadays there is an odd one that can be described as «1000 and 1 the most sophisticated and intricate ways to despise MRI’s garbage collector». Let’s figure out why there are so many people who hate it, how interpreter’s memory management works in general and what all this means to a down-to-earth Ruby developer who just needs to fix that goddamn memory leak.

Arthur Pirogovski

May 31, 2013
Tweet

More Decks by Arthur Pirogovski

Other Decks in Programming

Transcript

  1. What’s wrong with Ruby? • not as fast as some

    languages • concurrency is a swear word
  2. What’s wrong with Ruby? • not as fast as some

    languages • concurrency is a swear word • garbage collector is garbage
  3. Lifetime of an object rb_newobj(): 1. try to bite from

    freelist 2. if freelist is empty invoke GC
  4. Lifetime of an object rb_newobj(): 1. try to bite from

    freelist (except for basic types) 2. if freelist is empty invoke GC
  5. 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)
  6. 1. Stop the World 2. Mark all the linked objects

    3. Sweep until enough GC in 1.9
  7. 1. Stop the World 2. Mark all the linked objects

    3. Sweep until enough 4. malloc() if not enough GC in 1.9
  8. 1. Stop the World 2. Mark all the linked objects

    3. Sweep until enough 4. malloc() if not enough 5. Wake up the World GC in 1.9
  9. • no working memory profiler • no memory profiling API

    • borked finalizers In Ruby we have:
  10. • no working memory profiler • no memory profiling API

    • borked finalizers • ObjectSpace! In Ruby we have:
  11. ObjectSpace.each_object. reduce(Hash.new(0)) { |hash, o| hash[o.class] +=1; hash } helps

    to find leaks in custom Ruby types like ActiveRecord ObjectSpace?
  12. it works, but it’s: • slow • intrusive (allocates objects)

    • unable to show code location ObjectSpace?
  13. No such thing to reveal where an object was allocated

    But we can hack it up! Showing code location
  14. 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
  15. 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
  16. # 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
  17. • caller_locations versus caller is orders of magnitude faster and

    thus can replace caller in the original allocations_map Ruby 2.0