модуль 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
Общедоступные методы класса
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_callinfo);
INIT_IMEMO_TYPE_ID(imemo_callcache);
INIT_IMEMO_TYPE_ID(imemo_constcache);
INIT_IMEMO_TYPE_ID(imemo_fields);
#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.
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.
static VALUE
count_objects(int argc, VALUE *argv, VALUE os)
{
struct count_objects_data data = { 0 };
VALUE hash = Qnil;
VALUE types[T_MASK + 1];
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 (size_t i = 0; i <= T_MASK; i++) {
// type_sym can allocate an object,
// so we need to create all key symbols in advance
// not to disturb the result
types[i] = type_sym(i);
}
// Same as type_sym, we need to create all key symbols in advance
VALUE total = ID2SYM(rb_intern("TOTAL"));
VALUE free = ID2SYM(rb_intern("FREE"));
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, total, SIZET2NUM(data.total));
rb_hash_aset(hash, free, SIZET2NUM(data.freed));
for (size_t i = 0; i <= T_MASK; i++) {
if (data.counts[i]) {
rb_hash_aset(hash, types[i], 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.
Этот метод предназначен только для разработчиков MRI, интересующихся производительностью и использованием памяти программами Ruby.
Если передан необязательный аргумент result_hash, он перезаписывается и возвращается. Это позволяет избежать эффекта наблюдателя.
Примечание: содержимое возвращаемого хеша определяется реализацией и может измениться в будущем.
Предполагается, что этот метод работает только в C Ruby.
В этой версии MRI предусмотрено 3 типа символов (и один общий счетчик).
* 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.
Этот метод предназначен только для разработчиков 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.
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].
Рекомендуются два способа: создать процедуру-финализатор в методе, не являющемся методом экземпляра, где она сможет безопасно захватить необходимое состояние, либо использовать собственный вызываемый объект, который явно хранит необходимое состояние в переменных экземпляра.
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 (или являются его подклассами). Возвращает количество найденных объектов. Немедленные объекты (например, Fixnums, статические Symbols true, false и nil) никогда не возвращаются.
Если блок не задан, вместо него возвращается перечислитель.
Job = Class.new
jobs = [Job.new, Job.new]
count = ObjectSpace.each_object(Job) {|x| p x }
puts "Total count: #{count}"
выводит:
#<Job:0x000000011d6cbbf0> #<Job:0x000000011d6cbc68> Total count: 2
Из-за текущей проблемы реализации Ractor этот метод не передаёт объекты, которыми нельзя делиться между Ractor, когда процесс работает в многопоточном режиме Ractor. Многопоточный режим Ractor включается при первом вызове Ractor.new. Дополнительные сведения см. на странице bugs.ruby-lang.org/issues/19387.
a = 12345678987654321 # shareable
b = [].freeze # shareable
c = {} # not shareable
ObjectSpace.each_object {|x| x } # yields a, b, and c
Ractor.new {} # enter multi-Ractor mode
ObjectSpace.each_object {|x| x } # does not yield c
# File gc.rb, line 594 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 = rb_class_super_of(obj);
break;
default:
rb_raise(rb_eArgError, "class or module is expected");
}
return wrap_klass_iow(super);
} - Особенность MRI
-
Возвращает внутренний суперкласс cls (Class или Module).
obj может быть экземпляром InternalObjectWrapper.
Обратите внимание: этот метод не следует использовать в приложении.
static VALUE
memsize_of_m(VALUE self, VALUE obj)
{
return SIZET2NUM(rb_obj_memsize_of(obj));
} Возвращает объём памяти в байтах, занимаемый obj.
Обратите внимание, что возвращаемый размер указан не полностью. Используйте эти сведения только как ПОДСКАЗКУ. В частности, размер T_DATA может быть указан неверно.
Предполагается, что этот метод работает только в CRuby.
Начиная с Ruby 3.2, при использовании распределения с переменной шириной он возвращает фактический размер используемого слота, а также дополнительную память, выделенную за пределами слота (например, для внешних строк, массивов или хеш-таблиц).
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».
Если на один и тот же объект «x» из «obj» ссылаются два или более раза, возвращаемый массив содержит только один объект «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);
} Запускает отслеживание выделения объектов для отладки GC. Если в приложении возникает ошибка BUG «… is T_NONE» (или подобная), попробуйте вызвать этот метод в начале приложения.
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 раз, трассировка остановится после n вызовов ::trace_object_allocations_stop.
static VALUE
undefine_final(VALUE os, VALUE obj)
{
return rb_undefine_finalizer(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).
Если 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).
Предполагается, что этот метод работает только в C Ruby. Это экспериментальный метод, который может измениться. В частности, совместимость сигнатуры функции и формата вывода с будущими версиями Ruby не гарантируется.
Закрытые методы экземпляра
# File gc.rb, line 594 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.