Spec-Zone.ru › Ruby 3.2

модуль 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)
{
    size_t nodes[NODE_LAST+1];
    enum node_type i;
    VALUE hash = setup_hash(argc, argv);

    for (i = 0; i <= NODE_LAST; i++) {
        nodes[i] = 0;
    }

    each_object_with_flags(cn_i, &nodes[0]);

    for (i=0; i<NODE_LAST; i++) {
        if (nodes[i] != 0) {
            VALUE node;
            switch (i) {
#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); goto set
                COUNT_NODE(NODE_SCOPE);
                COUNT_NODE(NODE_BLOCK);
                COUNT_NODE(NODE_IF);
                COUNT_NODE(NODE_UNLESS);
                COUNT_NODE(NODE_CASE);
                COUNT_NODE(NODE_CASE2);
                COUNT_NODE(NODE_CASE3);
                COUNT_NODE(NODE_WHEN);
                COUNT_NODE(NODE_IN);
                COUNT_NODE(NODE_WHILE);
                COUNT_NODE(NODE_UNTIL);
                COUNT_NODE(NODE_ITER);
                COUNT_NODE(NODE_FOR);
                COUNT_NODE(NODE_FOR_MASGN);
                COUNT_NODE(NODE_BREAK);
                COUNT_NODE(NODE_NEXT);
                COUNT_NODE(NODE_REDO);
                COUNT_NODE(NODE_RETRY);
                COUNT_NODE(NODE_BEGIN);
                COUNT_NODE(NODE_RESCUE);
                COUNT_NODE(NODE_RESBODY);
                COUNT_NODE(NODE_ENSURE);
                COUNT_NODE(NODE_AND);
                COUNT_NODE(NODE_OR);
                COUNT_NODE(NODE_MASGN);
                COUNT_NODE(NODE_LASGN);
                COUNT_NODE(NODE_DASGN);
                COUNT_NODE(NODE_GASGN);
                COUNT_NODE(NODE_IASGN);
                COUNT_NODE(NODE_CDECL);
                COUNT_NODE(NODE_CVASGN);
                COUNT_NODE(NODE_OP_ASGN1);
                COUNT_NODE(NODE_OP_ASGN2);
                COUNT_NODE(NODE_OP_ASGN_AND);
                COUNT_NODE(NODE_OP_ASGN_OR);
                COUNT_NODE(NODE_OP_CDECL);
                COUNT_NODE(NODE_CALL);
                COUNT_NODE(NODE_OPCALL);
                COUNT_NODE(NODE_FCALL);
                COUNT_NODE(NODE_VCALL);
                COUNT_NODE(NODE_QCALL);
                COUNT_NODE(NODE_SUPER);
                COUNT_NODE(NODE_ZSUPER);
                COUNT_NODE(NODE_LIST);
                COUNT_NODE(NODE_ZLIST);
                COUNT_NODE(NODE_VALUES);
                COUNT_NODE(NODE_HASH);
                COUNT_NODE(NODE_RETURN);
                COUNT_NODE(NODE_YIELD);
                COUNT_NODE(NODE_LVAR);
                COUNT_NODE(NODE_DVAR);
                COUNT_NODE(NODE_GVAR);
                COUNT_NODE(NODE_IVAR);
                COUNT_NODE(NODE_CONST);
                COUNT_NODE(NODE_CVAR);
                COUNT_NODE(NODE_NTH_REF);
                COUNT_NODE(NODE_BACK_REF);
                COUNT_NODE(NODE_MATCH);
                COUNT_NODE(NODE_MATCH2);
                COUNT_NODE(NODE_MATCH3);
                COUNT_NODE(NODE_LIT);
                COUNT_NODE(NODE_STR);
                COUNT_NODE(NODE_DSTR);
                COUNT_NODE(NODE_XSTR);
                COUNT_NODE(NODE_DXSTR);
                COUNT_NODE(NODE_EVSTR);
                COUNT_NODE(NODE_DREGX);
                COUNT_NODE(NODE_ONCE);
                COUNT_NODE(NODE_ARGS);
                COUNT_NODE(NODE_ARGS_AUX);
                COUNT_NODE(NODE_OPT_ARG);
                COUNT_NODE(NODE_KW_ARG);
                COUNT_NODE(NODE_POSTARG);
                COUNT_NODE(NODE_ARGSCAT);
                COUNT_NODE(NODE_ARGSPUSH);
                COUNT_NODE(NODE_SPLAT);
                COUNT_NODE(NODE_BLOCK_PASS);
                COUNT_NODE(NODE_DEFN);
                COUNT_NODE(NODE_DEFS);
                COUNT_NODE(NODE_ALIAS);
                COUNT_NODE(NODE_VALIAS);
                COUNT_NODE(NODE_UNDEF);
                COUNT_NODE(NODE_CLASS);
                COUNT_NODE(NODE_MODULE);
                COUNT_NODE(NODE_SCLASS);
                COUNT_NODE(NODE_COLON2);
                COUNT_NODE(NODE_COLON3);
                COUNT_NODE(NODE_DOT2);
                COUNT_NODE(NODE_DOT3);
                COUNT_NODE(NODE_FLIP2);
                COUNT_NODE(NODE_FLIP3);
                COUNT_NODE(NODE_SELF);
                COUNT_NODE(NODE_NIL);
                COUNT_NODE(NODE_TRUE);
                COUNT_NODE(NODE_FALSE);
                COUNT_NODE(NODE_ERRINFO);
                COUNT_NODE(NODE_DEFINED);
                COUNT_NODE(NODE_POSTEXE);
                COUNT_NODE(NODE_DSYM);
                COUNT_NODE(NODE_ATTRASGN);
                COUNT_NODE(NODE_LAMBDA);
                COUNT_NODE(NODE_ARYPTN);
                COUNT_NODE(NODE_FNDPTN);
                COUNT_NODE(NODE_HSHPTN);
                COUNT_NODE(NODE_ERROR);
#undef COUNT_NODE
              case NODE_LAST: break;
            }
            UNREACHABLE;
          set:
            rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
        }
    }
    return hash;
}

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

Этот метод предназначен только для разработчиков 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)
{
    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;
}

Подсчитывает все объекты, сгруппированные по типу.

Он возвращает хеш, например:

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

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

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

Если объект является обычным (доступным) объектом, ключ — это объект Class. Если объект не является обычным (внутренним) объектом, ключ — это имя символа, зарегистрированное с помощью 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);
    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 define_final0(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);
}

Вызывает блок один раз для каждого активного, не-немедленного объекта в этом процессе Ruby. Если задан module, вызывает блок только для тех классов или модулей, которые совпадают (или являются подклассом) module. Возвращает количество найденных объектов. Немедленные объекты (Fixnums, Symbols true, false, и nils) никогда не возвращаются. В примере ниже, 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 291
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 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));
}

Возвращает размер занимаемой объектом памяти в байтах.

Обратите внимание, что возвращаемый размер неполный. Вы должны обрабатывать эту информацию только как УКАЗАНИЕ. В частности, размер 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 может быть неверным.

Обратите внимание, что этот метод НЕ возвращает общий размер выделенной памяти.

Этот метод можно определить следующим кодом 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) → массив или nil Показать исходный код
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;
    }
}
Особенности 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 → словарь Показать исходный код
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 { блок } Показать исходный код
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 раз, то отслеживание остановится после вызова ::trace_object_allocations_stop n раз.

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

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

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

dump(obj[, output: :string]) → "{ ... }" Показать исходный код
dump(obj, output: :file) → #<File:/tmp/rubyobj20131125-88733-1xkfmpv.json>
dump(obj, output: :stdout) → nil
# File ext/objspace/lib/objspace.rb, line 25
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.

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

dump_all([output: :file]) → #<File:/tmp/rubyheap20131125-88469-laoj3v.json> Показать исходный код
dump_all(output: :stdout) → nil
dump_all(output: :string) → "{...}\n{...}\n..."
dump_all(output: File.open('heap.json','w')) → #<File:heap.json>
dump_all(output: :string, since: 42) → "{...}\n{...}\n..."
# File ext/objspace/lib/objspace.rb, line 86
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.

full должно быть булевым значением. Если true, будут выведены все слоты кучи, включая пустые (T_NONE).

since должно быть неотрицательным целым числом или nil.

Если since — положительное целое число, выводятся только объекты этой и более новых поколений. Текущее поколение можно получить с помощью GC::count. Объекты, выделенные без включения отслеживания выделения объектов, игнорируются. Подробнее см. ::trace_object_allocations.

Если since опущено или равно nil, выводятся все объекты.

shapes должно быть булевым значением или неотрицательным целым числом.

Если shapes — положительное целое число, выводятся только формы, которые новее, чем предоставленный идентификатор формы. Текущий идентификатор формы можно получить, используя RubyVM.stat(:next_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.

dump_shapes([output: :file]) → #<File:/tmp/rubyshapes20131125-88469-laoj3v.json> Показать исходный код
dump_shapes(output: :stdout) → nil
dump_shapes(output: :string) → "{...}\n{...}\n..."
dump_shapes(output: File.open('shapes.json','w')) → #<File:shapes.json>
dump_all(output: :string, since: 42) → "{...}\n{...}\n..."
# File ext/objspace/lib/objspace.rb, line 123
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.

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

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

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

garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true) Показать исходный код
# File gc.rb, line 291
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end

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

Spec-Zone.ru

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