模块 ObjectSpace
objspace 库扩展了 ObjectSpace
模块,并添加了一些方法来获取关于对象/内存管理的内部统计信息。
您需要 require 'objspace'
才能使用此扩展模块。
通常,如果您不了解 MRI 实现,则 不应该 使用此库。主要来说,此库适用于需要了解 MRI 内存使用情况的(内存)分析器开发人员和 MRI 开发人员。
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
公共类方法
来源
static VALUE allocation_class_path(VALUE self, VALUE obj) { struct allocation_info *info = lookup_allocation_info(obj); if (info && info->class_path) { return rb_str_new2(info->class_path); } else { return Qnil; } }
返回给定 object
的类。
class A def foo ObjectSpace::trace_object_allocations do obj = Object.new p "#{ObjectSpace::allocation_class_path(obj)}" end end end A.new.foo #=> "Class"
有关更多信息和示例,请参见 ::trace_object_allocations
。
来源
static VALUE allocation_generation(VALUE self, VALUE obj) { struct allocation_info *info = lookup_allocation_info(obj); if (info) { return SIZET2NUM(info->generation); } else { return Qnil; } }
返回给定 object
的垃圾回收器代数。
class B include ObjectSpace def foo trace_object_allocations do obj = Object.new p "Generation is #{allocation_generation(obj)}" end end end B.new.foo #=> "Generation is 3"
有关更多信息和示例,请参见 ::trace_object_allocations
。
来源
static VALUE allocation_method_id(VALUE self, VALUE obj) { struct allocation_info *info = lookup_allocation_info(obj); if (info) { return info->mid; } else { return Qnil; } }
返回给定 object
的方法标识符。
class A include ObjectSpace def foo trace_object_allocations do obj = Object.new p "#{allocation_class_path(obj)}##{allocation_method_id(obj)}" end end end A.new.foo #=> "Class#new"
有关更多信息和示例,请参见 ::trace_object_allocations
。
来源
static VALUE allocation_sourcefile(VALUE self, VALUE obj) { struct allocation_info *info = lookup_allocation_info(obj); if (info && info->path) { return rb_str_new2(info->path); } else { return Qnil; } }
返回给定 object
的源文件来源。
有关更多信息和示例,请参见 ::trace_object_allocations
。
来源
static VALUE allocation_sourceline(VALUE self, VALUE obj) { struct allocation_info *info = lookup_allocation_info(obj); if (info) { return INT2FIX(info->line); } else { return Qnil; } }
返回给定 object
的源文件中原始行号。
有关更多信息和示例,请参见 ::trace_object_allocations
。
来源
static VALUE count_imemo_objects(int argc, VALUE *argv, VALUE self) { VALUE hash = setup_hash(argc, argv); if (imemo_type_ids[0] == 0) { #define INIT_IMEMO_TYPE_ID(n) (imemo_type_ids[n] = rb_intern_const(#n)) INIT_IMEMO_TYPE_ID(imemo_env); INIT_IMEMO_TYPE_ID(imemo_cref); INIT_IMEMO_TYPE_ID(imemo_svar); INIT_IMEMO_TYPE_ID(imemo_throw_data); INIT_IMEMO_TYPE_ID(imemo_ifunc); INIT_IMEMO_TYPE_ID(imemo_memo); INIT_IMEMO_TYPE_ID(imemo_ment); INIT_IMEMO_TYPE_ID(imemo_iseq); INIT_IMEMO_TYPE_ID(imemo_tmpbuf); INIT_IMEMO_TYPE_ID(imemo_ast); INIT_IMEMO_TYPE_ID(imemo_parser_strterm); INIT_IMEMO_TYPE_ID(imemo_callinfo); INIT_IMEMO_TYPE_ID(imemo_callcache); INIT_IMEMO_TYPE_ID(imemo_constcache); #undef INIT_IMEMO_TYPE_ID } each_object_with_flags(count_imemo_objects_i, (void *)hash); return hash; }
计算每个 T_IMEMO
类型的对象。
此方法仅适用于对 Ruby 程序的性能和内存使用情况感兴趣的 MRI 开发人员。
它返回一个哈希,例如
{:imemo_ifunc=>8, :imemo_svar=>7, :imemo_cref=>509, :imemo_memo=>1, :imemo_throw_data=>1}
如果给出了可选参数 result_hash,则会覆盖并返回它。这样做是为了避免探测效应。
返回的哈希的内容是特定于实现的,并且将来可能会更改。
在此版本中,键是符号对象。
此方法仅有望在 C Ruby 上工作。
来源
static VALUE count_nodes(int argc, VALUE *argv, VALUE os) { return setup_hash(argc, argv); }
计算每个节点类型的节点。
此方法仅适用于对 Ruby 程序的性能和内存使用情况感兴趣的 MRI 开发人员。
它返回一个哈希,例如
{:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
如果给出了可选参数 result_hash,则会覆盖并返回它。这样做是为了避免探测效应。
注意:返回的哈希的内容是实现定义的。将来可能会更改。
此方法仅有望在 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; }
计算按类型分组的所有对象。
它返回一个哈希,例如
{ :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_size(int argc, VALUE *argv, VALUE os) { size_t counts[T_MASK+1]; size_t total = 0; enum ruby_value_type i; VALUE hash = setup_hash(argc, argv); for (i = 0; i <= T_MASK; i++) { counts[i] = 0; } each_object_with_flags(cos_i, &counts[0]); for (i = 0; i <= T_MASK; i++) { if (counts[i]) { VALUE type = type2sym(i); total += counts[i]; rb_hash_aset(hash, type, SIZET2NUM(counts[i])); } } rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total)); return hash; }
计算每种类型的对象大小(以字节为单位)。
请注意,此信息不完整。您需要将此信息视为仅为 提示。特别是,T_DATA 的总大小可能错误。
它返回一个哈希,例如
{:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
如果给出了可选参数 result_hash,则会覆盖并返回它。这样做是为了避免探测效应。
返回的哈希的内容是实现定义的。将来可能会更改。
此方法仅有望在 C Ruby 上工作。
来源
static VALUE count_symbols(int argc, VALUE *argv, VALUE os) { struct dynamic_symbol_counts dynamic_counts = {0, 0}; VALUE hash = setup_hash(argc, argv); size_t immortal_symbols = rb_sym_immortal_count(); each_object_with_flags(cs_i, &dynamic_counts); rb_hash_aset(hash, ID2SYM(rb_intern("mortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.mortal)); rb_hash_aset(hash, ID2SYM(rb_intern("immortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.immortal)); rb_hash_aset(hash, ID2SYM(rb_intern("immortal_static_symbol")), SIZET2NUM(immortal_symbols - dynamic_counts.immortal)); rb_hash_aset(hash, ID2SYM(rb_intern("immortal_symbol")), SIZET2NUM(immortal_symbols)); return hash; }
计算每种 Symbol
类型的符号。
此方法仅适用于对 Ruby 程序的性能和内存使用情况感兴趣的 MRI 开发人员。
如果给出了可选参数 result_hash,则会覆盖并返回它。这样做是为了避免探测效应。
注意:返回的哈希的内容是实现定义的。将来可能会更改。
此方法仅有望在 C Ruby 上工作。
在此 MRI 版本中,它们有 3 种类型的符号(和 1 个总计数)。
* mortal_dynamic_symbol: GC target symbols (collected by GC) * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC) * immortal_static_symbol: Immortal symbols (do not collected by GC) * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol)
来源
static VALUE count_tdata_objects(int argc, VALUE *argv, VALUE self) { VALUE hash = setup_hash(argc, argv); each_object_with_flags(cto_i, (void *)hash); return hash; }
计算每个 T_DATA
类型的对象。
此方法仅适用于对 Ruby 程序的性能和内存使用情况感兴趣的 MRI 开发人员。
它返回一个哈希,例如
{RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6, :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99, ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1, Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2} # T_DATA objects existing at startup on r32276.
如果给出了可选参数 result_hash,则会覆盖并返回它。这样做是为了避免探测效应。
返回的哈希的内容是特定于实现的,并且将来可能会更改。
如果对象是正常的(可访问的)对象,则键是 Class
对象。如果对象不是正常的(内部)对象,则键是由 rb_data_type_struct 注册的符号名称。
此方法仅有望在 C Ruby 上工作。
来源
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); }
添加 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 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); }
在此 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
来源
# File 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
GC.start
的别名
来源
static VALUE objspace_internal_class_of(VALUE self, VALUE obj) { VALUE klass; if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { obj = (VALUE)DATA_PTR(obj); } if (RB_TYPE_P(obj, T_IMEMO)) { return Qnil; } else { klass = CLASS_OF(obj); return wrap_klass_iow(klass); } }
- MRI 特定功能
-
返回 obj 的内部类。
obj 可以是 InternalObjectWrapper
的实例。
请注意,您不应在您的应用程序中使用此方法。
来源
static VALUE objspace_internal_super_of(VALUE self, VALUE obj) { VALUE super; if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { obj = (VALUE)DATA_PTR(obj); } switch (OBJ_BUILTIN_TYPE(obj)) { case T_MODULE: case T_CLASS: case T_ICLASS: super = RCLASS_SUPER(obj); break; default: rb_raise(rb_eArgError, "class or module is expected"); } return wrap_klass_iow(super); }
obj 可以是 InternalObjectWrapper
的实例。
请注意,您不应在您的应用程序中使用此方法。
来源
static VALUE memsize_of_m(VALUE self, VALUE obj) { return SIZET2NUM(rb_obj_memsize_of(obj)); }
返回 obj 消耗的内存大小(以字节为单位)。
请注意,返回的大小不完整。您需要将此信息视为仅为 提示。特别是,T_DATA
的大小可能不正确。
此方法仅有望在 C Ruby 上工作。
从 Ruby 2.2 开始,memsize_of
(obj) 返回的内存大小包括 sizeof(RVALUE)。
来源
static VALUE memsize_of_all_m(int argc, VALUE *argv, VALUE self) { struct total_data data = {0, 0}; if (argc > 0) { rb_scan_args(argc, argv, "01", &data.klass); } each_object_with_flags(total_i, &data); return SIZET2NUM(data.total); }
返回所有活动对象消耗的内存大小(以字节为单位)。
如果给出了 klass
(应为 Class
对象),则返回给定类的实例的总内存大小。
请注意,返回的大小不完整。您需要将此信息视为仅为 提示。特别是,T_DATA
的大小可能不正确。
请注意,此方法 不 返回 malloc 的总内存大小。
此方法可以通过以下 Ruby 代码定义
def memsize_of_all klass = false total = 0 ObjectSpace.each_object{|e| total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass) } total end
此方法仅有望在 C Ruby 上工作。
来源
static VALUE reachable_objects_from(VALUE self, VALUE obj) { if (!RB_SPECIAL_CONST_P(obj)) { struct rof_data data; if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { obj = (VALUE)DATA_PTR(obj); } data.refs = rb_obj_hide(rb_ident_hash_new()); data.values = rb_ary_new(); rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data); return data.values; } else { return Qnil; } }
- MRI 特定功能
-
返回从 'obj' 可访问的所有对象。
此方法返回从 'obj' 可访问的所有对象。
如果 'obj' 对同一对象 'x' 有两个或多个引用,则返回的数组仅包含一个 'x' 对象。
如果 'obj' 是不可标记的(非堆管理)对象,例如 true、false、nil、符号和 Fixnum(和 Flonum),则它只返回 nil。
如果 'obj' 引用了内部对象,则它返回 ObjectSpace::InternalObjectWrapper
类的实例。此对象包含对内部对象的引用,您可以使用 'type' 方法检查内部对象的类型。
如果 'obj' 是 ObjectSpace::InternalObjectWrapper
类的实例,则此方法返回从 'obj' 指向的内部对象可访问的所有对象。
使用此方法,您可以找到内存泄漏。
此方法仅有望在 C Ruby 上工作。
示例
ObjectSpace.reachable_objects_from(['a', 'b', 'c']) #=> [Array, 'a', 'b', 'c'] ObjectSpace.reachable_objects_from(['a', 'a', 'a']) #=> [Array, 'a', 'a', 'a'] # all 'a' strings have different object id ObjectSpace.reachable_objects_from([v = 'a', v, v]) #=> [Array, 'a'] ObjectSpace.reachable_objects_from(1) #=> nil # 1 is not markable (heap managed) object
来源
static VALUE reachable_objects_from_root(VALUE self) { struct rofr_data data; VALUE hash = data.categories = rb_ident_hash_new(); data.last_category = 0; rb_objspace_reachable_objects_from_root(reachable_object_from_root_i, &data); rb_hash_foreach(hash, collect_values_of_values, hash); return hash; }
- MRI 特定功能
-
返回从根可访问的所有对象。
来源
static VALUE trace_object_allocations(VALUE self) { trace_object_allocations_start(self); return rb_ensure(rb_yield, Qnil, trace_object_allocations_stop, self); }
开始从 ObjectSpace
扩展模块跟踪对象分配。
例如
require 'objspace' class C include ObjectSpace def foo trace_object_allocations do obj = Object.new p "#{allocation_sourcefile(obj)}:#{allocation_sourceline(obj)}" end end end C.new.foo #=> "objtrace.rb:8"
此示例已包含 ObjectSpace
模块,以使其更易于阅读,但您也可以使用 ::trace_object_allocations
表示法(推荐)。
请注意,此功能会引入巨大的性能下降和巨大的内存消耗。
来源
static VALUE trace_object_allocations_clear(VALUE self) { struct traceobj_arg *arg = get_traceobj_arg(); /* clear tables */ st_foreach(arg->object_table, free_values_i, 0); st_clear(arg->object_table); st_foreach(arg->str_table, free_keys_i, 0); st_clear(arg->str_table); /* do not touch TracePoints */ return Qnil; }
清除记录的跟踪信息。
来源
static VALUE trace_object_allocations_debug_start(VALUE self) { tmp_keep_remains = 1; if (object_allocations_reporter_registered == 0) { object_allocations_reporter_registered = 1; rb_bug_reporter_add(object_allocations_reporter, 0); } return trace_object_allocations_start(self); }
来源
static VALUE trace_object_allocations_start(VALUE self) { struct traceobj_arg *arg = get_traceobj_arg(); if (arg->running++ > 0) { /* do nothing */ } else { if (arg->newobj_trace == 0) { arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg); arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg); } rb_tracepoint_enable(arg->newobj_trace); rb_tracepoint_enable(arg->freeobj_trace); } return Qnil; }
开始跟踪对象分配。
来源
static VALUE trace_object_allocations_stop(VALUE self) { struct traceobj_arg *arg = get_traceobj_arg(); if (arg->running > 0) { arg->running--; } if (arg->running == 0) { if (arg->newobj_trace != 0) { rb_tracepoint_disable(arg->newobj_trace); } if (arg->freeobj_trace != 0) { rb_tracepoint_disable(arg->freeobj_trace); } } return Qnil; }
停止跟踪对象分配。
请注意,如果 ::trace_object_allocations_start
被调用 n 次,则在调用 ::trace_object_allocations_stop
n 次后,跟踪将停止。
来源
static VALUE undefine_final(VALUE os, VALUE obj) { rb_check_frozen(obj); rb_gc_impl_undefine_finalizer(rb_gc_get_objspace(), obj); return obj; }
删除 obj 的所有终结器。
公共实例方法
来源
# File ext/objspace/lib/objspace.rb, line 28 def dump(obj, output: :string) out = case output when :file, nil require 'tempfile' Tempfile.create(%w(rubyobj .json)) when :stdout STDOUT when :string +'' when IO output else raise ArgumentError, "wrong output option: #{output.inspect}" end ret = _dump(obj, out) return nil if output == :stdout ret end
将 Ruby 对象的内容转储为 JSON
。
output 可以是以下之一::stdout
、:file
、:string
或 IO
对象。
-
:file
表示转储到临时文件并返回相应的File
对象; -
:stdout
表示打印转储内容并返回nil
; -
:string
表示返回包含转储内容的字符串; -
如果提供了
IO
对象的实例,则输出将发送到该对象,并返回该对象。
此方法仅预期在 C Ruby 中工作。这是一个实验性方法,可能会发生更改。 特别是,该函数的签名和输出格式不保证在 Ruby 的未来版本中兼容。
来源
# File ext/objspace/lib/objspace.rb, line 84 def dump_all(output: :file, full: false, since: nil, shapes: true) out = case output when :file, nil require 'tempfile' Tempfile.create(%w(rubyheap .json)) when :stdout STDOUT when :string +'' when IO output else raise ArgumentError, "wrong output option: #{output.inspect}" end shapes = 0 if shapes == true ret = _dump_all(out, full, since, shapes) return nil if output == :stdout ret end
将 Ruby 堆的内容转储为 JSON
。
output 参数与 dump
的相同。
full 必须是布尔值。 如果为 true,则会转储所有堆槽,包括空槽(T_NONE
)。
since 必须是非负整数或 nil
。
如果 since 是一个正整数,则仅转储该代和更新代的对象的对象。可以使用 GC::count
访问当前代。将忽略在未启用对象分配跟踪的情况下分配的对象。 有关更多信息和示例,请参见 ::trace_object_allocations
。
如果省略 since 或为 nil
,则会转储所有对象。
shapes 必须是布尔值或非负整数。
如果 shapes 是一个正整数,则仅转储比提供的 shape id 更新的形状。可以使用 RubyVM.stat(:next_shape_id)
访问当前 shape_id。
如果 shapes 为 false
,则不转储任何形状。
要仅转储在某个时间点之后分配的对象,您可以组合 since 和 shapes
ObjectSpace.trace_object_allocations GC.start gc_generation = GC.count shape_generation = RubyVM.stat(:next_shape_id) call_method_to_instrument ObjectSpace.dump_all(since: gc_generation, shapes: shape_generation)
此方法仅预期在 C Ruby 中工作。这是一个实验性方法,可能会发生更改。 特别是,该函数的签名和输出格式不保证在 Ruby 的未来版本中兼容。
来源
# File ext/objspace/lib/objspace.rb, line 116 def dump_shapes(output: :file, since: 0) out = case output when :file, nil require 'tempfile' Tempfile.create(%w(rubyshapes .json)) when :stdout STDOUT when :string +'' when IO output else raise ArgumentError, "wrong output option: #{output.inspect}" end ret = _dump_shapes(out, since) return nil if output == :stdout ret end
将 Ruby 形状树的内容转储为 JSON
。
output 参数与 dump
的相同。
如果 since 是一个正整数,则仅转储比提供的 shape id 更新的形状。可以使用 RubyVM.stat(:next_shape_id)
访问当前 shape_id。
此方法仅预期在 C Ruby 中工作。这是一个实验性方法,可能会发生更改。 特别是,该函数的签名和输出格式不保证在 Ruby 的未来版本中兼容。
私有实例方法
来源
# File 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
GC.start
的别名