Spec-Zone.ru › Ruby 3.4

модуль 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) → string Показать исходный код
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.

allocation_generation(object) → integer or nil Показать исходный код
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.

allocation_method_id(object) → string Показать исходный код
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.

allocation_sourcefile(object) → string Показать исходный код
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.

allocation_sourceline(object) → integer Показать исходный код
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.

count_imemo_objects([result_hash]) → hash Показать исходный код
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.

Этот метод предназначен только для разработчиков MRI, интересующихся производительностью и использованием памяти программ на Ruby.

Метод возвращает хеш следующего вида:

{:imemo_ifunc=>8,
 :imemo_svar=>7,
 :imemo_cref=>509,
 :imemo_memo=>1,
 :imemo_throw_data=>1}

Если указан необязательный аргумент result_hash, он перезаписывается и возвращается. Это предназначено для предотвращения влияния измерений.

Содержимое возвращаемого хеша зависит от реализации и может измениться в будущем.

В этой версии ключами являются объекты-символы.

Ожидается, что этот метод будет работать только с C Ruby.

count_nodes([result_hash]) → hash Показать исходный код
static VALUE
count_nodes(int argc, VALUE *argv, VALUE os)
{
    return setup_hash(argc, argv);
}

Подсчитывает узлы каждого типа.

Этот метод предназначен только для разработчиков MRI, интересующихся производительностью и использованием памяти программ на Ruby.

Метод возвращает хеш следующего вида:

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

Если указан необязательный аргумент result_hash, он перезаписывается и возвращается. Это предназначено для предотвращения влияния измерений.

Примечание: содержимое возвращаемого хеша определяется реализацией и может измениться в будущем.

Ожидается, что этот метод будет работать только с C Ruby.

count_objects([result_hash]) → hash Показать исходный код
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.

count_objects_size([result_hash]) → hash Показать исходный код
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.

count_symbols([result_hash]) → hash Показать исходный код
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.

Этот метод предназначен только для разработчиков MRI, интересующихся производительностью и использованием памяти программ на Ruby.

Если указан необязательный аргумент 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)
count_tdata_objects([result_hash]) → hash Показать исходный код
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.

Этот метод предназначен только для разработчиков MRI, интересующихся производительностью и использованием памяти программ на Ruby.

Метод возвращает хеш следующего вида:

{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, он перезаписывается и возвращается. Это предназначено для предотвращения влияния измерений.

Содержимое возвращаемого хеша зависит от реализации и может измениться в будущем.

В этой версии ключами являются объекты класса или объекты Symbol.

Если объект относится к обычным (доступным) объектам, ключом будет объект класса. Если объект не относится к обычным (внутренним) объектам, ключом будет имя символа, зарегистрированное с помощью rb_data_type_struct.

Ожидается, что этот метод будет работать только с C Ruby.

define_finalizer(obj, aProc=proc()) Показать исходный код
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 будет передан в aProc как аргумент. Если aProc — лямбда или метод, убедитесь, что его можно вызвать с одним аргументом.

Возвращаемое значение — массив [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

Также учтите, что финализация может быть непредсказуемой и гарантированно выполняется только при завершении программы.

each_object([module]) {|obj| ... } → integer Показать исходный код
each_object([module]) → an_enumerator
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);
}

Вызывает блок один раз для каждого живого не immediate-объекта в этом процессе Ruby. Если указан module, блок вызывается только для классов или модулей, соответствующих module (или являющихся его подклассами). Возвращает количество найденных объектов. Immediate-объекты (Fixnums, Symbols 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
garbage_collect (full_mark: true, immediate_mark: true, immediate_sweep: true) Показать исходный код
# 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

internal_class_of(obj) → Class or Module Показать исходный код
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.

Обратите внимание, что не следует использовать этот метод в приложении.

internal_super_of(cls) → Class or Module Показать исходный код
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);
}
Особенность MRI

Возвращает внутренний суперкласс cls (Class или Module).

obj может быть экземпляром InternalObjectWrapper.

Обратите внимание, что не следует использовать этот метод в приложении.

memsize_of(obj) → Integer Показать исходный код
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).

memsize_of_all([klass]) → Integer Показать исходный код
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.

reachable_objects_from(obj) → array or nil Показать исходный код
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, символы и Fixnums (и 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
reachable_objects_from_root → hash Показать исходный код
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

Возвращает все объекты, достижимые от корневых объектов.

trace_object_allocations { block } Показать исходный код
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 (рекомендуется).

Обратите внимание, что эта функция значительно снижает производительность и существенно увеличивает потребление памяти.

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 Показать исходный код
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 раз, трассировка остановится после n вызовов ::trace_object_allocations_stop.

undefine_finalizer(obj) Показать исходный код
static VALUE
undefine_final(VALUE os, VALUE obj)
{
    return rb_undefine_finalizer(obj);
}

Удаляет все финализаторы для obj.

Публичные методы экземпляра

dump (obj, output: :string) Показать исходный код
# 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 не гарантируется.

dump_all (output: :file, full: false, since: nil, shapes: true) Показать исходный код
# 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 — положительное целое число, дамп создаётся только для структур shapes с идентификатором новее указанного. Текущий shape_id можно получить с помощью RubyVM.stat(:next_shape_id).

Если shapes равен false, структуры shapes не включаются в дамп.

Чтобы создать дамп только объектов, выделенных после определённого момента, можно совместно использовать аргументы 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 не гарантируется.

dump_shapes (output: :file, since: 0) Показать исходный код
# 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

Создаёт дамп содержимого дерева shapes Ruby в формате JSON.

Аргумент output такой же, как у dump.

Если since — положительное целое число, дамп создаётся только для структур shapes с идентификатором новее указанного. Текущий shape_id можно получить с помощью RubyVM.stat(:next_shape_id).

Ожидается, что этот метод будет работать только с C Ruby. Это экспериментальный метод, который может измениться. В частности, совместимость сигнатуры функции и формата вывода в будущих версиях Ruby не гарантируется.

Приватные методы экземпляра

garbage_collect (full_mark: true, immediate_mark: true, immediate_sweep: true) Показать исходный код
# 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

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API