Память руби изнутри

  • View
    511

  • Download
    1

Embed Size (px)

DESCRIPTION

 

Transcript

  • 1. Ruby

2. , passenger 3. 4. MRI - (heap) sizeof(RVALUE) = 40 () 5. ObjectSpace _id2ref count_objects each_object garbage_collect dene_nalizer / undene_nalizer 6. Use the Source, Luke! 7. ObjectSpaceRVALUEObjectSpaceHeapRVALUE... freelistRVALUEHeap Heap freeRVALUE free freeRVALUE 8. GCRUBY_GC_MALLOC_LIMIT 8 RUBY_HEAP_MIN_SLOTS 10k 1.9.2 17k , 2.0.0 15kRUBY_FREE_MIN 4096 9. 2.0.0dev :001 > ObjectSpace.each_object(Hash){} => 1182.0.0dev :002 > ObjectSpace.each_object(Fixnum){} => 02.0.0dev :003 > ObjectSpace.each_object(Symbol){} => 0 10. - 11. Object ID2.0.0dev :001 > 0.object_id => 12.0.0dev :002 > 1.object_id => 32.0.0dev :003 > :a.object_id => 4688082.0.0dev :004 > "a".object_id => 701990559543802.0.0dev :005 > true.object_id => 202.0.0dev :006 > false.object_id => 02.0.0dev :007 > nil.object_id => 8 12. Object IDFixnum ag RUBY_Qfalse = 0x00, 101010101011 1RUBY_Qtrue= 0x14, RUBY_Qnil = 0x08, RUBY_Qundef = 0x34, Symbol id 1100RUBY_IMMEDIATE_MASK RUBY_FIXNUM_FLAG = = 0x07, 0x01, RUBY_FLONUM_MASK= 0x03, RUBY_FLONUM_FLAG= 0x02, RUBY_SYMBOL_FLAG= 0x0c, RVALUE ptr 000RUBY_SPECIAL_SHIFT= 8 13. enum ruby_value_type {RBasicRUBY_T_NONE = 0x00, RUBY_T_OBJECT = 0x01, RUBY_T_CLASS =0x02, RUBY_T_MODULE = 0x03, RUBY_T_FLOAT =0x04, RUBY_T_STRING = 0x05, RUBY_T_REGEXP = 0x06, RUBY_T_ARRAY =0x07, RUBY_T_HASH=0x08, RUBY_T_STRUCT = 0x09, RUBY_T_BIGNUM = 0x0a, RUBY_T_FILE=0x0b, struct RBasic { RUBY_T_DATA=0x0c, VALUE flags;RUBY_T_MATCH =0x0d, RUBY_T_COMPLEX= 0x0e, VALUE klass;RUBY_T_RATIONAL = 0x0f, };RUBY_T_NIL= 0x11, RUBY_T_TRUE = 0x12, RUBY_T_FALSE= 0x13, RUBY_T_SYMBOL = 0x14, RUBY_T_FIXNUM = 0x15, RUBY_T_UNDEF= 0x1b, RUBY_T_NODE = 0x1c, RUBY_T_ICLASS = 0x1d, RUBY_T_ZOMBIE = 0x1e, RUBY_T_MASK = 0x1f}; 14. RObject #define ROBJECT_EMBED_LEN_MAX 3 struct RObject {struct RBasic {VALUE flags;VALUE klass;};union {! struct { !long numiv;! VALUE *ivptr;struct st_table *iv_index_tbl; ivars[numiv]! } heap; ! VALUE ary[ROBJECT_EMBED_LEN_MAX];} as; }; 15. RClass struct RClass { struct RBasic basic; rb_classext_t *ptr; struct st_table *m_tbl; struct st_table *iv_index_tbl; }; struct rb_classext_struct { VALUE super; struct st_table *iv_tbl; struct st_table *const_tbl; VALUE origin; VALUE refined_class; rb_alloc_func_t allocator; }; 16. T_DATA struct RTypedData { struct RBasic basic; const rb_data_type_t *type; VALUE typed_flag; /* 1 or not */ void *data; }; struct rb_data_type_struct { const char *wrap_struct_name; struct { ! void (*dmark)(void*); ! void (*dfree)(void*); ! size_t (*dsize)(const void *); ! void *reserved[2]; } function; const rb_data_type_t *parent; void *data; }; 17. typedef struct RVALUE { union { !struct { !VALUE flags; !struct RVALUE *next;RVALUE ! ! !} free;struct RBasic basic;struct RObject object; !struct RClass klass; - RVALUE! !struct RFloat flonum;struct RString string; !struct RArray array;union ! !struct RRegexp regexp;struct RHash hash; !struct RData data; !struct RTypedData typeddata; !struct RStruct rstruct; !struct RBignum bignum; !struct RFile file; 40 ! !struct RNode node;struct RMatch match; !struct RRational rational; !struct RComplex complex; } as; } RVALUE; 18. RubyVM : Generic ivars Finalizers at_exit 19. Obj1 Obj2Obj4 Obj3 Obj5Obj7Obj6 20. Obj1 Obj2Obj4 Obj3 Obj5Obj7Obj6 21. 1 2Obj1 2 Obj2 1Obj4 1Obj3 1 Obj5 1 1 Obj7Obj6 1 22. Mark & Sweep: mark Obj1 Obj2Obj4 Obj3 Obj5Obj7Obj6 23. Mark & Sweep: mark Obj1 Obj2Obj4 Obj3 Obj5Obj7Obj6 24. Mark & Sweep: sweep Obj1 Obj2Obj4 Obj3 25. 26. class Adef a &b; end;def initializea(&:to_s)endenddef closure_methodA.newendclosure_methodGC.startputs ObjectSpace.each_object(A){} ? 27. WTF? 28. - T_CLASS, T_ICLASS T_MODULE T_DATAiseq = instruction sequencemethodblockproc = iseq + VM/env 29. 30. ? 31. heap_dumphttps://github.com/Vasfed/heap_dump 32. class A def a &b; end; def initialize a(&:to_s) end end def closure_method A.new end closure_method require heap_dump HeapDump.dump 33. $ grep "name":"A" dump.json,{"id":70129858139840,"bt":"T_CLASS","class":70129858139820,"name":"A","methods":{"a":70129857754000,"initialize":70129858140300}}$ grep 70129858139840 dump.json | grep T_OBJECT,{"id":70129858139780,"bt":"T_OBJECT","class":70129858139840}$ grep 70129858139780 dump.json | grep -v id":70129858139780,{"id":70129858139720,"bt":"T_DATA","class":70129857815360,"type_name":"VM/env","size":104,"env":[70129858139780,70129858139720],"local_size":2,...$ grep 70129858139720 dump.json | grep -v id":70129858139720,{"id":70129858139700,"bt":"T_DATA","type_name":"proc","envval":70129858139720,"block":{"iseq":70129858139740,"self":"to_s"}$ grep 70129858139700 dump.json | grep -v id":70129858139700,{"id":70129858139760,"bt":"T_ARRAY","class":null,"val":[null,null,null,null,...,null,null,"to_s",70129858139700,null,null,...]} 34. class Aobject AVM/env- 134 proc proc 35. //string.cstatic VALUE sym_to_proc(VALUE sym){static VALUE sym_proc_cache = Qfalse;enum {SYM_PROC_CACHE_SIZE = 67};... if (!sym_proc_cache) {! sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2);! rb_gc_register_mark_object(sym_proc_cache);!... index = (id % SYM_PROC_CACHE_SIZE) HeapDump.count_objects([:ApplicationController] + ApplicationController.subclasses.map{|c| c.name.to_sym}) end def dump fork { HeapDump.dump; exit } render :text => "May be Dumped" end end 40. $ curl http://localhost:3000/count { "total_slots": 183152, "free_slots": 53535, "basic_types": { "T_OBJECT": 5064, "T_CLASS": 2723, "T_MODULE": 423, "T_FLOAT": 82, "T_STRING": 74909, "T_REGEXP": 1235, "T_ARRAY": 21019, "T_HASH": 585, "T_STRUCT": 199, "T_BIGNUM": 2, "T_FILE": 8, "T_DATA": 12741, "T_MATCH": 4, "T_COMPLEX": 1, "T_RATIONAL": 69, "T_NODE": 10038, "T_ICLASS": 515 }, "user_types": { "LeakController": 7 } } 41. $ grep name":"LeakController" dump.json | grep T_CLASS,{"id":70281018730340,"bt":"T_CLASS","class":70281018730260,"name":"LeakController","methods":{"_layout":70281018415040,"leak":70281029395580,"count":70281029394940,"dump":70281029394280, ...},"ivs":{"__classpath__":"LeakController","@controller_name":"leak","@visible_actions":70281018559740,"@controller_path":"leak","@_layout":null,"@action_methods":70281004447860,"@parent_name":null,"@parent_prefixes":70281009406480,"@_config":70281007802340,"@view_context_class":70281004125560},"super":70281029346060} 42. $ grep 70211925295180 dump.json ,{"id":70211925285360,"bt":"T_DATA","class":70211923570840,"type_name":"proc","size":72,"is_lambda":0,"blockprocval":null,"envval":70211925285380,"block":{"iseq":{"id":70211951312640,"name":"block inleak","filename":"/Users/vasfed/work/railsclub/examples/leaky_app/app/controllers/leak_controller.rb","line":5,"type":"block","refs_array_id":70211931351000,"coverage":null,"klass":null,"cref_stack":70211931351600,"defined_method_id":0},"self":70211925295180,"lfp":70211950222292,"dfp":70211950222292}} 43. LeakControllerLeakControllerLeakController...procprocproc $leakglobal_tbl 44. Prot! 45. @@aa = selfEventMachine.next_tick {...}Symbol#to_proc aka &:symbol / 46. ? ObjectSpace GC 47. ???https://github.com/Vasfed/heap_dumphttps://gist.github.com/4273437@vasfed