Module: ObjectSpace

Defined in:
gc.c

Overview

The ObjectSpace module contains a number of routines that interact with the garbage collection facility and allow you to traverse all living objects with an iterator.

ObjectSpace also provides support for object finalizers, procs that will be called when a specific object is about to be destroyed by garbage collection.

include ObjectSpace

a = "A"
b = "B"
c = "C"

define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
define_finalizer(a, proc {|id| puts "Finalizer two on #{id}" })
define_finalizer(b, proc {|id| puts "Finalizer three on #{id}" })

produces:

Finalizer three on 537763470
Finalizer one on 537763480
Finalizer two on 537763480

Class Method Summary collapse

Class Method Details

._id2ref(object_id) ⇒ Object

Converts an object id to a reference to the object. May not be called on an object id passed as a parameter to a finalizer.

s = "I am a string"                    #=> "I am a string"
r = ObjectSpace._id2ref(s.object_id)   #=> "I am a string"
r == s                                 #=> true

Returns:



# File 'gc.c'

/*
 *  call-seq:
 *     ObjectSpace._id2ref(object_id) -> an_object
 *
 *  Converts an object id to a reference to the object. May not be
 *  called on an object id passed as a parameter to a finalizer.
 *
 *     s = "I am a string"                    #=> "I am a string"
 *     r = ObjectSpace._id2ref(s.object_id)   #=> "I am a string"
 *     r == s                                 #=> true
 *
 */

static VALUE
id2ref(VALUE obj, VALUE objid)
{
#if SIZEOF_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULONG(x)
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULL(x)
#endif
    rb_objspace_t *objspace = &rb_objspace;
    VALUE ptr;
    void *p0;

    rb_secure(4);
    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;
    ptr = objid ^ FIXNUM_FLAG;  /* unset FIXNUM_FLAG */

    if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
        ID symid = ptr / sizeof(RVALUE);
        if (rb_id2name(symid) == 0)
        rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
    return ID2SYM(symid);
    }

    if (!is_pointer_to_heap(objspace, (void *)ptr) ||
    BUILTIN_TYPE(ptr) > T_FIXNUM || BUILTIN_TYPE(ptr) == T_ICLASS) {
    rb_raise(rb_eRangeError, "%p is not id value", p0);
    }
    if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
    rb_raise(rb_eRangeError, "%p is recycled object", p0);
    }
    return (VALUE)ptr;
}

.count_objects([result_hash]) ⇒ Hash

Counts objects for each type.

It returns a hash as: :FREE=>3011, :T_OBJECT=>6, :T_CLASS=>404, ...

If the optional argument, result_hash, is given, it is overwritten and returned. This is intended to avoid probe effect.

The contents of the returned hash is implementation defined. It may be changed in future.

This method is not expected to work except C Ruby.

Returns:



# File 'gc.c'

/*
 *  call-seq:
 *     ObjectSpace.count_objects([result_hash]) -> hash
 *
 *  Counts objects for each type.
 *
 *  It returns a hash as:
 *  {:TOTAL=>10000, :FREE=>3011, :T_OBJECT=>6, :T_CLASS=>404, ...}
 *
 *  If the optional argument, result_hash, is given,
 *  it is overwritten and returned.
 *  This is intended to avoid probe effect.
 *
 *  The contents of the returned hash is implementation defined.
 *  It may be changed in future.
 *
 *  This method is not expected to work except C Ruby.
 *
 */

static VALUE
count_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;

    if (rb_scan_args(argc, argv, "01", &hash) == 1) {
        if (TYPE(hash) != T_HASH)
            rb_raise(rb_eTypeError, "non-hash given");
    }

    for (i = 0; i <= T_MASK; i++) {
        counts[i] = 0;
    }

    for (i = 0; i < heaps_used; i++) {
        RVALUE *p, *pend;

        p = heaps[i].slot; pend = p + heaps[i].limit;
        for (;p < pend; p++) {
            if (p->as.basic.flags) {
                counts[BUILTIN_TYPE(p)]++;
            }
            else {
                freed++;
            }
        }
        total += heaps[i].limit;
    }

    if (hash == Qnil) {
        hash = rb_hash_new();
    }
    else if (!RHASH_EMPTY_P(hash)) {
        st_foreach(RHASH_TBL(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;
        switch (i) {
#define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
        COUNT_TYPE(T_NONE);
        COUNT_TYPE(T_OBJECT);
        COUNT_TYPE(T_CLASS);
        COUNT_TYPE(T_MODULE);
        COUNT_TYPE(T_FLOAT);
        COUNT_TYPE(T_STRING);
        COUNT_TYPE(T_REGEXP);
        COUNT_TYPE(T_ARRAY);
        COUNT_TYPE(T_HASH);
        COUNT_TYPE(T_STRUCT);
        COUNT_TYPE(T_BIGNUM);
        COUNT_TYPE(T_FILE);
        COUNT_TYPE(T_DATA);
        COUNT_TYPE(T_MATCH);
        COUNT_TYPE(T_COMPLEX);
        COUNT_TYPE(T_RATIONAL);
        COUNT_TYPE(T_NIL);
        COUNT_TYPE(T_TRUE);
        COUNT_TYPE(T_FALSE);
        COUNT_TYPE(T_SYMBOL);
        COUNT_TYPE(T_FIXNUM);
        COUNT_TYPE(T_UNDEF);
        COUNT_TYPE(T_NODE);
        COUNT_TYPE(T_ICLASS);
        COUNT_TYPE(T_ZOMBIE);
#undef COUNT_TYPE
          default:              type = INT2NUM(i); break;
        }
        if (counts[i])
            rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
    }

    return hash;
}

.define_finalizer(obj, aProc = proc()) ⇒ Object

Adds aProc as a finalizer, to be called after obj was destroyed.



# File 'gc.c'

/*
 *  call-seq:
 *     ObjectSpace.define_finalizer(obj, aProc=proc())
 *
 *  Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
 *  was destroyed.
 *
 */

static VALUE
define_final(int argc, VALUE *argv, VALUE os)
{
    rb_objspace_t *objspace = &rb_objspace;
    VALUE obj, block, table;

    rb_scan_args(argc, argv, "11", &obj, &block);
    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
    if (argc == 1) {
    block = rb_block_proc();
    }
    else if (!rb_respond_to(block, rb_intern("call"))) {
    rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
         rb_obj_classname(block));
    }
    if (!FL_ABLE(obj)) {
    rb_raise(rb_eArgError, "cannot define finalizer for %s",
         rb_obj_classname(obj));
    }
    RBASIC(obj)->flags |= FL_FINALIZE;

    block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
    OBJ_FREEZE(block);

    if (!finalizer_table) {
    finalizer_table = st_init_numtable();
    }
    if (st_lookup(finalizer_table, obj, &table)) {
    rb_ary_push(table, block);
    }
    else {
    table = rb_ary_new3(1, block);
    RBASIC(table)->klass = 0;
    st_add_direct(finalizer_table, obj, table);
    }
    return block;
}

.each_object([) {|obj| ... } ⇒ Fixnum .each_object([) ⇒ Object

Calls the block once for each living, nonimmediate object in this Ruby process. If module is specified, calls the block for only those classes or modules that match (or are a subclass of) module. Returns the number of objects found. Immediate objects (Fixnums, Symbols true, false, and nil) are never returned. In the example below, each_object returns both the numbers we defined and several constants defined in the Math module.

If no block is given, an enumerator is returned instead.

a = 102.7
b = 95       # Won't be returned
c = 12345678987654321
count = ObjectSpace.each_object(Numeric) {|x| p x }
puts "Total count: #{count}"

produces:

12345678987654321
102.7
2.71828182845905
3.14159265358979
2.22044604925031e-16
1.7976931348623157e+308
2.2250738585072e-308
Total count: 7

Overloads:

  • .each_object([) {|obj| ... } ⇒ Fixnum

    Yields:

    • (obj)

    Returns:



# File 'gc.c'

/*
 *  call-seq:
 *     ObjectSpace.each_object([module]) {|obj| ... } -> fixnum
 *     ObjectSpace.each_object([module])              -> an_enumerator
 *
 *  Calls the block once for each living, nonimmediate object in this
 *  Ruby process. If <i>module</i> is specified, calls the block
 *  for only those classes or modules that match (or are a subclass of)
 *  <i>module</i>. Returns the number of objects found. Immediate
 *  objects (<code>Fixnum</code>s, <code>Symbol</code>s
 *  <code>true</code>, <code>false</code>, and <code>nil</code>) are
 *  never returned. In the example below, <code>each_object</code>
 *  returns both the numbers we defined and several constants defined in
 *  the <code>Math</code> module.
 *
 *  If no block is given, an enumerator is returned instead.
 *
 *     a = 102.7
 *     b = 95       # Won't be returned
 *     c = 12345678987654321
 *     count = ObjectSpace.each_object(Numeric) {|x| p x }
 *     puts "Total count: #{count}"
 *
 *  <em>produces:</em>
 *
 *     12345678987654321
 *     102.7
 *     2.71828182845905
 *     3.14159265358979
 *     2.22044604925031e-16
 *     1.7976931348623157e+308
 *     2.2250738585072e-308
 *     Total count: 7
 *
 */

static VALUE
os_each_obj(int argc, VALUE *argv, VALUE os)
{
    VALUE of;

    rb_secure(4);
    if (argc == 0) {
    of = 0;
    }
    else {
    rb_scan_args(argc, argv, "01", &of);
    }
    RETURN_ENUMERATOR(os, 1, &of);
    return os_obj_of(of);
}

.startnil .garbage_collectnil .garbage_collectnil

Initiates garbage collection, unless manually disabled.

Overloads:

  • .startnil

    Returns:

    • (nil)
  • .garbage_collectnil

    Returns:

    • (nil)
  • .garbage_collectnil

    Returns:

    • (nil)


# File 'gc.c'

/*
 *  call-seq:
 *     GC.start                     -> nil
 *     gc.garbage_collect           -> nil
 *     ObjectSpace.garbage_collect  -> nil
 *
 *  Initiates garbage collection, unless manually disabled.
 *
 */

VALUE
rb_gc_start(void)
{
    rb_gc();
    return Qnil;
}

.undefine_finalizer(obj) ⇒ Object

Removes all finalizers for obj.



# File 'gc.c'

/*
 *  call-seq:
 *     ObjectSpace.undefine_finalizer(obj)
 *
 *  Removes all finalizers for <i>obj</i>.
 *
 */

static VALUE
undefine_final(VALUE os, VALUE obj)
{
    rb_objspace_t *objspace = &rb_objspace;
    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
    if (finalizer_table) {
    st_delete(finalizer_table, (st_data_t*)&obj, 0);
    }
    FL_UNSET(obj, FL_FINALIZE);
    return obj;
}