模块 ObjectSpace
ObjectSpace 模块包含许多与垃圾回收机制交互的例程,并允许您使用迭代器遍历所有活动对象。
ObjectSpace 还为对象终结器提供支持,这些终结器是将在特定对象被垃圾回收销毁后调用的 proc。有关如何正确使用此方法的重要信息,请参阅 ObjectSpace.define_finalizer 的文档。
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
产生
Finalizer two on 537763470 Finalizer one on 537763480
公共类方法
按类型对所有对象进行计数。
它返回一个哈希,例如
{
:TOTAL=>10000,
:FREE=>3011,
:T_OBJECT=>6,
:T_CLASS=>404,
# ...
}
返回的哈希的内容是特定于实现的。它可能会在未来发生变化。
以 :T_ 开头的键表示活动对象。例如,:T_ARRAY 是数组的数量。:FREE 表示当前未使用的对象槽。:TOTAL 表示以上各项的总和。
如果给出了可选参数 result_hash,则会覆盖并返回它。这旨在避免探测效应。
h = {} ObjectSpace.count_objects(h) puts h # => { :TOTAL=>10000, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249 }
此方法预计仅在 C Ruby 上工作。
static VALUE
count_objects(int argc, VALUE *argv, VALUE os)
{
struct count_objects_data data = { 0 };
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");
}
rb_gc_impl_each_object(rb_gc_get_objspace(), count_objects_i, &data);
if (NIL_P(hash)) {
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(data.total));
rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(data.freed));
for (size_t i = 0; i <= T_MASK; i++) {
VALUE type = type_sym(i);
if (data.counts[i])
rb_hash_aset(hash, type, SIZET2NUM(data.counts[i]));
}
return hash;
}
添加 aProc 作为终结器,在 obj 被销毁后调用。obj 的对象 ID 将作为参数传递给 aProc。如果 aProc 是 lambda 或方法,请确保它可以被调用并接受一个参数。
返回值是一个数组 [0, aProc]。
两种推荐的模式是在非实例方法中创建终结器 proc,以便它可以安全地捕获所需的状态,或者使用自定义的可调用对象,该对象将所需的状态显式存储为实例变量。
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
请注意,如果您的终结器引用了要终结的对象,则它永远不会在 GC 上运行,尽管它仍然会在退出时运行。如果捕获要作为终结器的接收器的对象,您将收到警告。
class CapturesSelf def initialize(name) ObjectSpace.define_finalizer(self, proc { # this finalizer will only be run on exit puts "finalizing #{name}" }) end end
另请注意,终结是不可预测的,并且除非在退出时,否则永远无法保证运行。
static VALUE
define_final(int argc, VALUE *argv, VALUE os)
{
VALUE obj, block;
rb_scan_args(argc, argv, "11", &obj, &block);
if (argc == 1) {
block = rb_block_proc();
}
if (rb_callable_receiver(block) == obj) {
rb_warn("finalizer references object to be finalized");
}
return rb_define_finalizer(obj, block);
}
为这个 Ruby 进程中每个活动的、非立即对象调用一次块。如果指定了 module,则仅为那些匹配(或为 module 的子类)的类或模块调用该块。返回找到的对象数。立即对象(Fixnum、Symbol、true、false 和 nil)永远不会返回。在下面的示例中,each_object 返回我们定义的数字和 Math 模块中定义的几个常量。
如果没有给出块,则返回一个枚举器。
a = 102.7 b = 95 # Won't be returned c = 12345678987654321 count = ObjectSpace.each_object(Numeric) {|x| p x } puts "Total count: #{count}"
产生
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;
of = (!rb_check_arity(argc, 0, 1) ? 0 : argv[0]);
RETURN_ENUMERATOR(os, 1, &of);
return os_obj_of(of);
}
GC.start 的别名
# File ruby_3_4_1/gc.rb, line 395 def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false end
删除 obj 的所有终结器。
static VALUE
undefine_final(VALUE os, VALUE obj)
{
rb_check_frozen(obj);
rb_gc_impl_undefine_finalizer(rb_gc_get_objspace(), obj);
return obj;
}
私有实例方法
GC.start 的别名
# File ruby_3_4_1/gc.rb, line 395 def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false end