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.

   require 'objspace'

   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:



2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
# File 'gc.c', line 2941

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);
    }
    if (RBASIC(ptr)->klass == 0) {
  rb_raise(rb_eRangeError, "%p is internal object", p0);
    }
    return (VALUE)ptr;
}

.count_objects([result_hash]) ⇒ Hash

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 be changed in future.

The keys starting with :T_ means live objects. For example, :T_ARRAY is the number of arrays. :FREE means object slots which is not used now. :TOTAL means sum of above.

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

h = {}
ObjectSpace.count_objects(h)
puts h
# => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }

This method is only expected to work on C Ruby.

Returns:



3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
# File 'gc.c', line 3223

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_IMEMO);
      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. The object ID of the obj will be passed as an argument to aProc. If aProc is a lambda or method, make sure it can be called with a single argument.



2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
# File 'gc.c', line 2558

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:



2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
# File 'gc.c', line 2489

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)


6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
# File 'gc.c', line 6449

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.



2512
2513
2514
2515
2516
# File 'gc.c', line 2512

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:



2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
# File 'gc.c', line 2941

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);
    }
    if (RBASIC(ptr)->klass == 0) {
  rb_raise(rb_eRangeError, "%p is internal object", p0);
    }
    return (VALUE)ptr;
}

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

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 be changed in future.

The keys starting with :T_ means live objects. For example, :T_ARRAY is the number of arrays. :FREE means object slots which is not used now. :TOTAL means sum of above.

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

h = {}
ObjectSpace.count_objects(h)
puts h
# => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }

This method is only expected to work on C Ruby.

Returns:



3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
# File 'gc.c', line 3223

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_IMEMO);
      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. The object ID of the obj will be passed as an argument to aProc. If aProc is a lambda or method, make sure it can be called with a single argument.



2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
# File 'gc.c', line 2558

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:



2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
# File 'gc.c', line 2489

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)


6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
# File 'gc.c', line 6449

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.



2512
2513
2514
2515
2516
# File 'gc.c', line 2512

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