Module: ObjectSpace

Defined in:
gc.c,
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.

   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}" })

_produces:_

   Finalizer two on 537763470
   Finalizer one on 537763480

Defined Under Namespace

Classes: WeakMap

Class Method Summary collapse

Instance 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:



2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
# File 'gc.c', line 2729

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;

    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 % sizeof(RVALUE)) == (4 << 2)) {
        ID symid = ptr / sizeof(RVALUE);
        if (rb_id2str(symid) == 0)
	    rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
	return ID2SYM(symid);
    }

    if (!is_id_value(objspace, ptr)) {
	rb_raise(rb_eRangeError, "%p is not id value", p0);
    }
    if (!is_live_object(objspace, ptr)) {
	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, such as:

:TOTAL=>10000,
:FREE=>3011,
:T_OBJECT=>6,
:T_CLASS=>404,
# ...

The contents of the returned hash are implementation specific. It may be changed in future.

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

This method is only expected to work on C Ruby.

Returns:



2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
# File 'gc.c', line 2996

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 (!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++) {
	    if (p->as.basic.flags) {
		counts[BUILTIN_TYPE(p)]++;
	    }
	    else {
		freed++;
	    }
	}
	total += page->total_slots;
    }

    if (hash == Qnil) {
        hash = rb_hash_new();
    }
    else if (!RHASH_EMPTY_P(hash)) {
        st_foreach(RHASH_TBL_RAW(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.



2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
# File 'gc.c', line 2344

static VALUE
define_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);
    }

    return define_final0(obj, 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:



2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
# File 'gc.c', line 2277

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

    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 .start(full_mark: true, immediate_sweep: true) ⇒ nil .garbage_collect(full_mark: true, immediate_sweep: true) ⇒ nil

Initiates garbage collection, unless manually disabled.

This method is defined with keyword arguments that default to true:

def GC.start(full_mark: true, immediate_sweep: true); end

Use full_mark: false to perform a minor GC. Use immediate_sweep: false to defer sweeping (use lazy sweep).

Note: These keyword arguments are implementation and version dependent. They are not guaranteed to be future-compatible, and may be ignored if the underlying implementation does not support them.

Overloads:

  • .startnil

    Returns:

    • (nil)
  • .garbage_collectnil

    Returns:

    • (nil)
  • .start(full_mark: true, immediate_sweep: true) ⇒ nil

    Returns:

    • (nil)
  • .garbage_collect(full_mark: true, immediate_sweep: true) ⇒ nil

    Returns:

    • (nil)


6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
# File 'gc.c', line 6161

static VALUE
gc_start_internal(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = &rb_objspace;
    int full_mark = TRUE, immediate_mark = TRUE, immediate_sweep = TRUE;
    VALUE opt = Qnil;
    static ID keyword_ids[3];

    rb_scan_args(argc, argv, "0:", &opt);

    if (!NIL_P(opt)) {
	VALUE kwvals[3];

	if (!keyword_ids[0]) {
	    keyword_ids[0] = rb_intern("full_mark");
	    keyword_ids[1] = rb_intern("immediate_mark");
	    keyword_ids[2] = rb_intern("immediate_sweep");
	}

	rb_get_kwargs(opt, keyword_ids, 0, 3, kwvals);

	if (kwvals[0] != Qundef) full_mark = RTEST(kwvals[0]);
	if (kwvals[1] != Qundef) immediate_mark = RTEST(kwvals[1]);
	if (kwvals[2] != Qundef) immediate_sweep = RTEST(kwvals[2]);
    }

    garbage_collect(objspace, full_mark, immediate_mark, immediate_sweep, GPR_FLAG_METHOD);
    if (!finalizing) finalize_deferred(objspace);

    return Qnil;
}

.undefine_finalizer(obj) ⇒ Object

Removes all finalizers for obj.



2300
2301
2302
2303
2304
# File 'gc.c', line 2300

static VALUE
undefine_final(VALUE os, VALUE obj)
{
    return rb_undefine_finalizer(obj);
}

Instance Method Details

#_id2ref(object_id) ⇒ Object (private)

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:



2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
# File 'gc.c', line 2729

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;

    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 % sizeof(RVALUE)) == (4 << 2)) {
        ID symid = ptr / sizeof(RVALUE);
        if (rb_id2str(symid) == 0)
	    rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
	return ID2SYM(symid);
    }

    if (!is_id_value(objspace, ptr)) {
	rb_raise(rb_eRangeError, "%p is not id value", p0);
    }
    if (!is_live_object(objspace, ptr)) {
	rb_raise(rb_eRangeError, "%p is recycled object", p0);
    }
    return (VALUE)ptr;
}

#count_objects([result_hash]) ⇒ Hash (private)

Counts objects for each 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 be changed in future.

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

This method is only expected to work on C Ruby.

Returns:



2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
# File 'gc.c', line 2996

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 (!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++) {
	    if (p->as.basic.flags) {
		counts[BUILTIN_TYPE(p)]++;
	    }
	    else {
		freed++;
	    }
	}
	total += page->total_slots;
    }

    if (hash == Qnil) {
        hash = rb_hash_new();
    }
    else if (!RHASH_EMPTY_P(hash)) {
        st_foreach(RHASH_TBL_RAW(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 (private)

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



2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
# File 'gc.c', line 2344

static VALUE
define_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);
    }

    return define_final0(obj, block);
}

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

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:



2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
# File 'gc.c', line 2277

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

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

#startnil (private) #garbage_collectnil (private) #start(full_mark: true, immediate_sweep: true) ⇒ nil (private) #garbage_collect(full_mark: true, immediate_sweep: true) ⇒ nil (private)

Initiates garbage collection, unless manually disabled.

This method is defined with keyword arguments that default to true:

def GC.start(full_mark: true, immediate_sweep: true); end

Use full_mark: false to perform a minor GC. Use immediate_sweep: false to defer sweeping (use lazy sweep).

Note: These keyword arguments are implementation and version dependent. They are not guaranteed to be future-compatible, and may be ignored if the underlying implementation does not support them.

Overloads:

  • #startnil

    Returns:

    • (nil)
  • #garbage_collectnil

    Returns:

    • (nil)
  • #start(full_mark: true, immediate_sweep: true) ⇒ nil

    Returns:

    • (nil)
  • #garbage_collect(full_mark: true, immediate_sweep: true) ⇒ nil

    Returns:

    • (nil)


6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
# File 'gc.c', line 6161

static VALUE
gc_start_internal(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = &rb_objspace;
    int full_mark = TRUE, immediate_mark = TRUE, immediate_sweep = TRUE;
    VALUE opt = Qnil;
    static ID keyword_ids[3];

    rb_scan_args(argc, argv, "0:", &opt);

    if (!NIL_P(opt)) {
	VALUE kwvals[3];

	if (!keyword_ids[0]) {
	    keyword_ids[0] = rb_intern("full_mark");
	    keyword_ids[1] = rb_intern("immediate_mark");
	    keyword_ids[2] = rb_intern("immediate_sweep");
	}

	rb_get_kwargs(opt, keyword_ids, 0, 3, kwvals);

	if (kwvals[0] != Qundef) full_mark = RTEST(kwvals[0]);
	if (kwvals[1] != Qundef) immediate_mark = RTEST(kwvals[1]);
	if (kwvals[2] != Qundef) immediate_sweep = RTEST(kwvals[2]);
    }

    garbage_collect(objspace, full_mark, immediate_mark, immediate_sweep, GPR_FLAG_METHOD);
    if (!finalizing) finalize_deferred(objspace);

    return Qnil;
}

#undefine_finalizer(obj) ⇒ Object (private)

Removes all finalizers for obj.



2300
2301
2302
2303
2304
# File 'gc.c', line 2300

static VALUE
undefine_final(VALUE os, VALUE obj)
{
    return rb_undefine_finalizer(obj);
}