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. See the documentation for
<code>ObjectSpace.define_finalizer</code> for important information on
how to 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 = nil
b = nil
_produces:_
Finalizer two on 537763470
Finalizer one on 537763480
Defined Under Namespace
Classes: WeakMap
Class Method Summary collapse
- ._id2ref(objid) ⇒ Object
-
.count_objects([result_hash]) ⇒ Hash
Counts all objects grouped by type.
-
.define_finalizer(obj, aProc = proc()) ⇒ Object
Adds aProc as a finalizer, to be called after obj was destroyed.
-
.each_object(*args) ⇒ Object
Calls the block once for each living, nonimmediate object in this Ruby process.
-
.undefine_finalizer(obj) ⇒ Object
Removes all finalizers for obj.
Instance Method Summary collapse
- #_id2ref(objid) ⇒ Object private
-
#count_objects([result_hash]) ⇒ Hash
private
Counts all objects grouped by type.
-
#define_finalizer(obj, aProc = proc()) ⇒ Object
private
Adds aProc as a finalizer, to be called after obj was destroyed.
-
#each_object(*args) ⇒ Object
private
Calls the block once for each living, nonimmediate object in this Ruby process.
-
#undefine_finalizer(obj) ⇒ Object
private
Removes all finalizers for obj.
Class Method Details
._id2ref(objid) ⇒ Object
4029 4030 4031 4032 4033 |
# File 'gc.c', line 4029
static VALUE
os_id2ref(VALUE os, VALUE objid)
{
return id2ref(objid);
}
|
.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.
4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 |
# File 'gc.c', line 4395
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 = 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;
}
|
.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.
The return value is an array [0, aProc]
.
The two recommended patterns are to either create the finaliser proc in a non-instance method where it can safely capture the needed state, or to use a custom callable object that stores the needed state explicitly as instance variables.
class Foo
def initialize(data_needed_for_finalization)
ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
end
def self.create_finalizer(data_needed_for_finalization)
proc {
puts "finalizing #{data_needed_for_finalization}"
}
end
end
class Bar
class Remover
def initialize(data_needed_for_finalization)
@data_needed_for_finalization = data_needed_for_finalization
end
def call(id)
puts "finalizing #{@data_needed_for_finalization}"
end
end
def initialize(data_needed_for_finalization)
ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
end
end
Note that if your finalizer references the object to be finalized it will never be run on GC, although it will still be run at exit. You will get a warning if you capture the object to be finalized as the receiver of the finalizer.
class CapturesSelf
def initialize(name)
ObjectSpace.define_finalizer(self, proc {
# this finalizer will only be run on exit
puts "finalizing #{name}"
})
end
end
Also note that finalization can be unpredictable and is never guaranteed to be run except on exit.
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 |
# File 'gc.c', line 3547
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);
}
if (rb_callable_receiver(block) == obj) {
rb_warn("finalizer references object to be finalized");
}
return define_final0(obj, block);
}
|
.each_object([) {|obj| ... } ⇒ Integer .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 (Fixnum
s, Symbol
s 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
3431 3432 3433 3434 3435 3436 3437 3438 3439 |
# File 'gc.c', line 3431
static VALUE
os_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);
}
|
.undefine_finalizer(obj) ⇒ Object
Removes all finalizers for obj.
3449 3450 3451 3452 3453 |
# File 'gc.c', line 3449
static VALUE
undefine_final(VALUE os, VALUE obj)
{
return rb_undefine_finalizer(obj);
}
|
Instance Method Details
#_id2ref(objid) ⇒ Object (private)
4029 4030 4031 4032 4033 |
# File 'gc.c', line 4029
static VALUE
os_id2ref(VALUE os, VALUE objid)
{
return id2ref(objid);
}
|
#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.
4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 |
# File 'gc.c', line 4395
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 = 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;
}
|
#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.
The return value is an array [0, aProc]
.
The two recommended patterns are to either create the finaliser proc in a non-instance method where it can safely capture the needed state, or to use a custom callable object that stores the needed state explicitly as instance variables.
class Foo
def initialize(data_needed_for_finalization)
ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
end
def self.create_finalizer(data_needed_for_finalization)
proc {
puts "finalizing #{data_needed_for_finalization}"
}
end
end
class Bar
class Remover
def initialize(data_needed_for_finalization)
@data_needed_for_finalization = data_needed_for_finalization
end
def call(id)
puts "finalizing #{@data_needed_for_finalization}"
end
end
def initialize(data_needed_for_finalization)
ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
end
end
Note that if your finalizer references the object to be finalized it will never be run on GC, although it will still be run at exit. You will get a warning if you capture the object to be finalized as the receiver of the finalizer.
class CapturesSelf
def initialize(name)
ObjectSpace.define_finalizer(self, proc {
# this finalizer will only be run on exit
puts "finalizing #{name}"
})
end
end
Also note that finalization can be unpredictable and is never guaranteed to be run except on exit.
3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 |
# File 'gc.c', line 3547
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);
}
if (rb_callable_receiver(block) == obj) {
rb_warn("finalizer references object to be finalized");
}
return define_final0(obj, block);
}
|
#each_object([) {|obj| ... } ⇒ Integer (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 (Fixnum
s, Symbol
s 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
3431 3432 3433 3434 3435 3436 3437 3438 3439 |
# File 'gc.c', line 3431
static VALUE
os_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);
}
|
#undefine_finalizer(obj) ⇒ Object (private)
Removes all finalizers for obj.
3449 3450 3451 3452 3453 |
# File 'gc.c', line 3449
static VALUE
undefine_final(VALUE os, VALUE obj)
{
return rb_undefine_finalizer(obj);
}
|