模块 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