Class: ObjspaceHelpers
- Inherits:
-
Object
- Object
- ObjspaceHelpers
- Defined in:
- lib/objspace_helpers/leaks.rb,
lib/objspace_helpers/helpers.rb,
lib/objspace_helpers/version.rb
Defined Under Namespace
Classes: TrackedObject
Constant Summary collapse
- VERSION =
'0.0.3'
Class Method Summary collapse
- ._addresses_to_info(ary) ⇒ Object
- ._addresses_to_references(addresses) ⇒ Object
- ._dump_addresses ⇒ Object
- ._id2ref(objid) ⇒ Object
- .diff(&block) ⇒ Object
- .dump_all_addresses ⇒ Object
- .find_leak_sources(trace: false, &block) ⇒ Object
- .find_leaks(trace: false, &block) ⇒ Object
- .info_for_address(addresses) ⇒ Object
- .info_for_obj(obj) ⇒ Object
Class Method Details
._addresses_to_info(ary) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'ext/objspace_helpers/objspace_helpers.c', line 24
static VALUE oh_addresses_to_info(VALUE self, VALUE ary)
{
VALUE hash, obj_addr, info_hash;
long i;
hash = rb_hash_new();
for (i = 0; i < RARRAY_LEN(ary); i += 1) {
obj_addr = rb_ary_entry(ary, i);
info_hash = rb_hash_new();
objspace_info(oh_id2ref(self, obj_addr), info_hash);
rb_hash_aset(hash, obj_addr, info_hash);
}
return hash;
}
|
._addresses_to_references(addresses) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'ext/objspace_helpers/objspace_helpers.c', line 47
static VALUE oh_addresses_to_references(VALUE self, VALUE addresses)
{
VALUE hash, obj_addr, references;
long i;
hash = rb_hash_new();
for (i = 0; i < RARRAY_LEN(addresses); i += 1) {
obj_addr = rb_ary_entry(addresses, i);
references = rb_ary_new();
rb_objspace_reachable_objects_from(oh_id2ref(self, obj_addr), reachable_object_i, (void*)references);
rb_hash_aset(hash, obj_addr, references);
}
return hash;
}
|
._dump_addresses ⇒ Object
17 18 19 20 21 22 |
# File 'ext/objspace_helpers/objspace_helpers.c', line 17
static VALUE oh_dump_addresses(VALUE self)
{
VALUE ary = rb_ary_new();
rb_objspace_each_objects(collect_addresses, (void *)ary);
return ary;
}
|
._id2ref(objid) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'ext/objspace_helpers/id2ref.c', line 18
VALUE
oh_id2ref(VALUE self, VALUE objid)
{
#if SIZEOF_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULONG(x)
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULL(x)
#endif
VALUE ptr;
void *p0;
ptr = NUM2PTR(objid);
p0 = (void *)ptr;
if (ptr == Qtrue) return Qtrue;
if (ptr == Qfalse) return Qfalse;
if (ptr == Qnil) return Qnil;
if (FIXNUM_P(ptr)) return (VALUE)ptr;
if (FLONUM_P(ptr)) return (VALUE)ptr;
ptr = obj_id_to_ref(objid);
if ((ptr % rb_intern("RVALUE_SIZE")) == (4 << 2)) {
ID symid = ptr / rb_intern("RVALUE_SIZE");
if (rb_id2name(symid) == 0) return Qundef;
return ID2SYM(symid);
}
return (VALUE)ptr;
}
|
.diff(&block) ⇒ Object
14 15 16 17 18 19 |
# File 'lib/objspace_helpers/helpers.rb', line 14 def self.diff(&block) objs_before = dump_all_addresses block.call objs_after = dump_all_addresses objs_after - objs_before - [objs_after.object_id] end |
.dump_all_addresses ⇒ Object
2 3 4 |
# File 'lib/objspace_helpers/helpers.rb', line 2 def self.dump_all_addresses _dump_addresses end |
.find_leak_sources(trace: false, &block) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/objspace_helpers/leaks.rb', line 36 def find_leak_sources(trace: false, &block) leaks = find_leaks(trace: trace, &block) leaks_by_source = {} top_level_leaks = [] leaks.each do |leak| if leak.referenced_by.empty? top_level_leaks << leak else leak.referenced_by.each do |source| leaks_by_source[source] ||= [] leaks_by_source[source] << leak end end end [top_level_leaks, leaks_by_source] end |
.find_leaks(trace: false, &block) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/objspace_helpers/leaks.rb', line 3 def find_leaks(trace: false, &block) ObjectSpace::trace_object_allocations_start if trace objs_before = _dump_addresses block.call # Run GC twice to try to get rid of as much false positives as possible ObjectSpace.garbage_collect ObjectSpace.garbage_collect objs_after = _dump_addresses ObjectSpace::trace_object_allocations_stop if trace leaked_addresses = objs_after - objs_before - [objs_after.object_id] GC.disable # Note (LukasFittl): 2x speedup if we move this to native code referenced_by = {} _addresses_to_references(objs_after).each do |addr, references| (references & leaked_addresses).each do |ref| referenced_by[ref] ||= [] referenced_by[ref] << addr end end GC.enable TrackedObject.wrap(leaked_addresses, referenced_by) end |
.info_for_address(addresses) ⇒ Object
6 7 8 |
# File 'lib/objspace_helpers/helpers.rb', line 6 def self.info_for_address(addresses) _addresses_to_info(addresses) end |
.info_for_obj(obj) ⇒ Object
10 11 12 |
# File 'lib/objspace_helpers/helpers.rb', line 10 def self.info_for_obj(obj) _addresses_to_info([obj.object_id]).values.first end |