ObjectSpace 模組

objspace 函式庫擴充了 ObjectSpace 模組,並新增了數個方法來取得物件/記憶體管理的內部統計資訊。

您需要 require 'objspace' 才能使用這個擴充模組。

一般來說,如果您不瞭解 MRI 實作,則不應該使用這個函式庫。這個函式庫主要是提供給 (記憶體) 分析程式開發人員和需要瞭解 MRI 記憶體使用狀況的 MRI 開發人員。

ObjectSpace 模組包含了許多與垃圾回收機制互動的常式,並允許您使用迭代器來遍歷所有存在的物件。

ObjectSpace 也提供物件終結器的支援,當垃圾回收器準備銷毀特定物件時,會呼叫這些程序。請參閱 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

公開類別方法

allocation_class_path(object) → 字串 按一下以切換來源

傳回給定 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_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;
    }
}
allocation_generation(object) → 整數或 nil 按一下以切換來源

傳回給定 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_generation(VALUE self, VALUE obj)
{
    struct allocation_info *info = lookup_allocation_info(obj);
    if (info) {
        return SIZET2NUM(info->generation);
    }
    else {
        return Qnil;
    }
}
allocation_method_id(object) → 字串 按一下以切換來源

傳回給定 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_method_id(VALUE self, VALUE obj)
{
    struct allocation_info *info = lookup_allocation_info(obj);
    if (info) {
        return info->mid;
    }
    else {
        return Qnil;
    }
}
allocation_sourcefile(object) → 字串 按一下以切換來源

傳回給定 object 的來源檔案來源。

請參閱 ::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;
    }
}
allocation_sourceline(object) → 整數 按一下以切換來源

傳回給定 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;
    }
}
count_imemo_objects([result_hash]) → 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_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;
}
count_nodes([result_hash]) → hash 按一下以切換來源

計算每個節點類型的節點。

此方法僅供有興趣了解 Ruby 程式效能和記憶體使用狀況的 MRI 開發人員使用。

它傳回一個雜湊,如下所示:

{:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}

如果提供選用引數 result_hash,它會被覆寫並傳回。這是為了避免探測效應。

注意:傳回雜湊的內容是由實作定義的。它可能會在未來變更。

此方法預期僅能搭配 C Ruby 使用。

static VALUE
count_nodes(int argc, VALUE *argv, VALUE os)
{
    return setup_hash(argc, argv);
}
count_objects([result_hash]) → 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(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];
        short stride = page->slot_size;

        uintptr_t p = (uintptr_t)page->start;
        uintptr_t pend = p + page->total_slots * stride;
        for (;p < pend; p += stride) {
            VALUE vp = (VALUE)p;
            GC_ASSERT((NUM_IN_PAGE(vp) * BASE_SLOT_SIZE) % page->slot_size == 0);

            void *poisoned = asan_unpoison_object_temporary(vp);
            if (RANY(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 (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(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;
}
count_objects_size([result_hash]) → hash 按一下以切換來源

計算每個類型的物件大小(以位元組為單位)。

請注意,此資訊並不完整。您需要將此資訊視為僅供 參考。特別是,T_DATA 的總大小可能不正確。

它傳回一個雜湊,如下所示:

{:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}

如果提供選用引數 result_hash,它會被覆寫並傳回。這是為了避免探測效應。

傳回雜湊的內容是由實作定義的。它可能會在未來變更。

此方法預期僅能搭配 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;
}
count_symbols([result_hash]) → 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_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;
}
count_tdata_objects([result_hash]) → 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 物件或 Symbol 物件。

如果物件是正常(可存取)物件,金鑰是 Class 物件。如果物件不是正常(內部)物件,金鑰是 rb_data_type_struct 註冊的符號名稱。

此方法預期僅能搭配 C Ruby 使用。

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;
}
define_finalizer(obj, aProc=proc()) 按一下以切換來源

aProc 新增為完成處理函式,在 obj 毀損後呼叫。obj 的物件 ID 會作為引數傳遞給 aProc。如果 aProc 是 lambda 或方法,請確定它可以用單一引數呼叫。

傳回值是陣列 [0, aProc]

建議使用兩種模式:在非執行個體方法中建立完成處理函式,在其中可以安全擷取所需的狀態,或使用自訂可呼叫物件,將所需的狀態明確儲存為執行個體變數。

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);
    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 rb_define_finalizer_no_check(obj, block);
}
each_object([module]) {|obj| ... } → integer 按一下以切換來源
each_object([module]) → enumerator

針對此 Ruby 程序中每個存在的非立即物件呼叫區塊一次。如果指定 module,僅針對與 module 相符(或為其子類別)的那些類別或模組呼叫區塊。傳回找到的物件數目。立即物件(FixnumSymboltruefalsenil)永遠不會傳回。在以下範例中,each_object 傳回我們定義的數字和 Math 模組中定義的幾個常數。

如果沒有提供區塊,會傳回 enumerator。

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);
}
garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true) 按一下以切換來源

別名為 GC.start

# File gc.rb, line 327
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
internal_class_of(obj) → Class 或 Module 按一下以切換來源
MRI 特定功能

傳回 obj 的內部類別。

obj 可以是 InternalObjectWrapper 的實例。

請注意,您不應在應用程式中使用此方法。

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);
    }
}
internal_super_of(cls) → Class 或 Module 按一下以切換來源
MRI 特定功能

傳回 cls 的內部超類別 (ClassModule)。

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);
}
memsize_of(obj) → Integer 按一下以切換來源

傳回 obj 消耗的記憶體大小(以位元組為單位)。

請注意,傳回的大小並不完整。您需要將此資訊視為僅供 參考。特別是,T_DATA 的大小可能不正確。

此方法預期僅能搭配 C Ruby 使用。

從 Ruby 2.2 開始,memsize_of(obj) 傳回的記憶體大小包含 sizeof(RVALUE)。

static VALUE
memsize_of_m(VALUE self, VALUE obj)
{
    return SIZET2NUM(rb_obj_memsize_of(obj));
}
memsize_of_all([klass]) → Integer 按一下以切換來源

傳回所有現存物件消耗的記憶體大小(以位元組為單位)。

如果給定 klass(應為 Class 物件),傳回給定類別實例的總記憶體大小。

請注意,傳回的大小並不完整。您需要將此資訊視為僅供 參考。特別是,T_DATA 的大小可能不正確。

請注意,此方法 不會 傳回總共配置的記憶體大小。

此方法可透過下列 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
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);
}
reachable_objects_from(obj) → 陣列或 nil 按一下以切換來源
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(VALUE self, VALUE obj)
{
    if (rb_objspace_markable_object_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;
    }
}
reachable_objects_from_root → hash 按一下以切換來源
MRI 特定功能

傳回從根部可到達的所有物件。

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;
}
trace_object_allocations { block } 按一下以切換來源

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(VALUE self)
{
    trace_object_allocations_start(self);
    return rb_ensure(rb_yield, Qnil, trace_object_allocations_stop, self);
}
trace_object_allocations_clear 按一下以切換來源

清除已記錄的追蹤資訊。

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;
}
trace_object_allocations_debug_start() 按一下以切換來源
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);
}
trace_object_allocations_start 按一下以切換來源

開始追蹤物件配置。

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;
}
trace_object_allocations_stop 按一下以切換來源

停止追蹤物件配置。

請注意,如果呼叫 ::trace_object_allocations_start n 次,則在呼叫 ::trace_object_allocations_stop n 次後,追蹤將會停止。

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;
}
undefine_finalizer(obj) 按一下以切換來源

移除 obj 的所有 finalizer。

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

公開實例方法

dump(obj, output: :string) 按一下以切換來源

將 ruby 物件的內容轉儲為 JSON

output 可以是下列其中一項::stdout:file:stringIO 物件。

  • :file 表示轉儲至暫存檔並傳回對應的 File 物件;

  • :stdout 表示列印轉儲並傳回 nil

  • :string 表示傳回包含轉儲的字串;

  • 如果提供 IO 物件的實例,輸出會轉至該處,並傳回該物件。

此方法預期只能與 C Ruby 一起使用。這是個實驗性質的方法,可能會變更。特別是,函式簽章和輸出格式無法保證與未來版本的 ruby 相容。

# 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
dump_all(output: :file, full: false, since: nil, shapes: true) 按一下以切換來源

將 ruby 堆疊的內容轉儲為 JSON

output 參數與 dump 相同。

full 必須是布林值。如果為 true,則會轉儲所有堆疊槽,包括空的槽 (T_NONE)。

since 必須是非負整數或 nil

如果 since 是正整數,則僅傾印該世代及更新世代的物件。目前世代可以使用 GC::count 存取。已在未啟用物件配置追蹤的情況下配置的物件將會被忽略。請參閱 ::trace_object_allocations 以取得更多資訊和範例。

如果省略 since 或為 nil,則傾印所有物件。

shapes 必須是布林值或非負整數。

如果 shapes 是正整數,則僅傾印比提供的形狀 ID 更新的形狀。目前形狀 ID 可以使用 RubyVM.stat(:next_shape_id) 存取。

如果 shapesfalse,則不傾印任何形狀。

若要僅傾印超過特定時間點配置的物件,您可以結合使用 sinceshapes

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 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
dump_shapes(output: :file, since: 0) 按一下以切換來源

將 Ruby 形狀樹的內容傾印為 JSON

output 參數與 dump 相同。

如果 since 是正整數,則僅傾印比提供的形狀 ID 更新的形狀。目前形狀 ID 可以使用 RubyVM.stat(:next_shape_id) 存取。

此方法預期只能與 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

私人實例方法

garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true) 按一下以切換來源

別名為 GC.start

# File gc.rb, line 327
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end