TheObjectSpace module contains a number ofroutines that interact with the garbage collection facility and allow youto traverse all living objects with an iterator.
ObjectSpace also provides support for objectfinalizers, procs that will be called when a specific object is about to bedestroyed by garbage collection. See the documentation forObjectSpace.define_finalizer
for important information on howto use this method correctly.
a ="A"b ="B"ObjectSpace.define_finalizer(a,proc {|id|puts"Finalizer one on #{id}" })ObjectSpace.define_finalizer(b,proc {|id|puts"Finalizer two on #{id}" })a =nilb =nil
produces:
Finalizertwoon537763470Finalizeroneon537763480
static VALUEos_id2ref(VALUE os, VALUE objid){ return id2ref(objid);}
Counts all objects grouped by type.
It returns a hash, such as:
{ :TOTAL=>10000, :FREE=>3011, :T_OBJECT=>6, :T_CLASS=>404,# ...}
The contents of the returned hash are implementation specific. It may bechanged in future.
The keys starting with:T_
means live objects. For example,:T_ARRAY
is the number of arrays.:FREE
meansobject slots which is not used now.:TOTAL
means sum of above.
If the optional argumentresult_hash
is given, it isoverwritten and returned. This is intended to avoid probe effect.
h = {}ObjectSpace.count_objects(h)putsh# => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
This method is only expected to work on C Ruby.
static VALUEcount_objects(int argc, VALUE *argv, VALUE os){ rb_objspace_t *objspace = &rb_objspace; size_t counts[T_MASK+1]; size_t freed = 0; size_t total = 0; size_t i; VALUE hash = Qnil; if (rb_check_arity(argc, 0, 1) == 1) { hash = argv[0]; if (!RB_TYPE_P(hash, T_HASH)) rb_raise(rb_eTypeError, "non-hash given"); } for (i = 0; i <= T_MASK; i++) { counts[i] = 0; } for (i = 0; i < heap_allocated_pages; i++) { struct heap_page *page = heap_pages_sorted[i]; RVALUE *p, *pend; p = page->start; pend = p + page->total_slots; for (;p < pend; p++) { VALUE vp = (VALUE)p; void *poisoned = asan_poisoned_object_p(vp); asan_unpoison_object(vp, false); if (p->as.basic.flags) { counts[BUILTIN_TYPE(vp)]++; } else { freed++; } if (poisoned) { GC_ASSERT(BUILTIN_TYPE(vp) == T_NONE); asan_poison_object(vp); } } total += page->total_slots; } if (hash == Qnil) { hash = rb_hash_new(); } else if (!RHASH_EMPTY_P(hash)) { rb_hash_stlike_foreach(hash, set_zero, hash); } rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total)); rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed)); for (i = 0; i <= T_MASK; i++) { VALUE type = type_sym(i); if (counts[i]) rb_hash_aset(hash, type, SIZET2NUM(counts[i])); } return hash;}
AddsaProc as a finalizer, to be called afterobj wasdestroyed. The object ID of theobj will be passed as an argumenttoaProc. IfaProc is a lambda or method, make sure itcan be called with a single argument.
The return value is an array[0, aProc]
.
The two recommended patterns are to either create the finaliser proc in anon-instance method where it can safely capture the needed state, or to usea custom callable object that stores the needed state explicitly asinstance variables.
classFoodefinitialize(data_needed_for_finalization)ObjectSpace.define_finalizer(self,self.class.create_finalizer(data_needed_for_finalization))enddefself.create_finalizer(data_needed_for_finalization)proc {puts"finalizing #{data_needed_for_finalization}" }endendclassBarclassRemoverdefinitialize(data_needed_for_finalization)@data_needed_for_finalization =data_needed_for_finalizationenddefcall(id)puts"finalizing #{@data_needed_for_finalization}"endenddefinitialize(data_needed_for_finalization)ObjectSpace.define_finalizer(self,Remover.new(data_needed_for_finalization))endend
Note that if your finalizer references the object to be finalized it willnever be run onGC, although it will still be run atexit. You will get a warning if you capture the object to be finalized asthe receiver of the finalizer.
classCapturesSelfdefinitialize(name)ObjectSpace.define_finalizer(self,proc {# this finalizer will only be run on exitputs"finalizing #{name}" })endend
Also note that finalization can be unpredictable and is never guaranteed tobe run except on exit.
static VALUEdefine_final(int argc, VALUE *argv, VALUE os){ VALUE obj, block; rb_scan_args(argc, argv, "11", &obj, &block); should_be_finalizable(obj); if (argc == 1) { block = rb_block_proc(); } else { should_be_callable(block); } if (rb_callable_receiver(block) == obj) { rb_warn("finalizer references object to be finalized"); } return define_final0(obj, block);}
Calls the block once for each living, nonimmediate object in this Rubyprocess. Ifmodule is specified, calls the block for only thoseclasses or modules that match (or are a subclass of)module.Returns the number of objects found. Immediate objects(Fixnum
s,Symbol
strue
,false
, andnil
) are never returned. In theexample below, each_object returns both the numbers we defined and severalconstants defined in theMath module.
If no block is given, an enumerator is returned instead.
a =102.7b =95# Won't be returnedc =12345678987654321count =ObjectSpace.each_object(Numeric) {|x|px }puts"Total count: #{count}"
produces:
12345678987654321102.72.718281828459053.141592653589792.22044604925031e-161.7976931348623157e+3082.2250738585072e-308Totalcount:7
static VALUEos_each_obj(int argc, VALUE *argv, VALUE os){ VALUE of; of = (!rb_check_arity(argc, 0, 1) ? 0 : argv[0]); RETURN_ENUMERATOR(os, 1, &of); return os_obj_of(of);}
This page was generated for Ruby 3.0.0
Generated with Ruby-doc Rdoc Generator 0.42.0.