модуль ObjectSpace
Библиотека objspace расширяет модуль ObjectSpace и добавляет несколько методов для получения внутренней статистической информации об управлении объектами/памятью.
Вам нужно require 'objspace' для использования этого расширяемого модуля.
Как правило, вы *НЕ ДОЛЖНЫ* использовать эту библиотеку, если вы не знаете о реализации MRI. В основном, эта библиотека предназначена для разработчиков профилировщиков памяти и разработчиков MRI, которым нужно знать об использовании памяти MRI.
Модуль ObjectSpace содержит ряд процедур, взаимодействующих с механизмом сбора мусора и позволяющих вам пройти по всем активным объектам с помощью итератора.
ObjectSpace также поддерживает финализаторы объектов, процедуры, которые будут вызваны, когда конкретный объект собирается быть уничтожен сборкой мусора.
require 'objspace'
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}" })
производит:
Finalizer two on 537763470 Finalizer one on 537763480
Публичные методы класса
static VALUE
id2ref(VALUE obj, VALUE objid)
{
#if SIZEOF_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULONG(x)
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULL(x)
#endif
rb_objspace_t *objspace = &rb_objspace;
VALUE ptr;
void *p0;
ptr = NUM2PTR(objid);
p0 = (void *)ptr;
if (ptr == Qtrue) return Qtrue;
if (ptr == Qfalse) return Qfalse;
if (ptr == Qnil) return Qnil;
if (FIXNUM_P(ptr)) return (VALUE)ptr;
if (FLONUM_P(ptr)) return (VALUE)ptr;
ptr = obj_id_to_ref(objid);
if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
ID symid = ptr / sizeof(RVALUE);
if (rb_id2str(symid) == 0)
rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
return ID2SYM(symid);
}
if (!is_id_value(objspace, ptr)) {
rb_raise(rb_eRangeError, "%p is not id value", p0);
}
if (!is_live_object(objspace, ptr)) {
rb_raise(rb_eRangeError, "%p is recycled object", p0);
}
if (RBASIC(ptr)->klass == 0) {
rb_raise(rb_eRangeError, "%p is internal object", p0);
}
return (VALUE)ptr;
} Преобразует идентификатор объекта в ссылку на объект. Нельзя вызывать для идентификатора объекта, переданного в качестве параметра финализатору.
s = "I am a string" #=> "I am a string" r = ObjectSpace._id2ref(s.object_id) #=> "I am a string" r == s #=> true
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) {
imemo_type_ids[0] = rb_intern("imemo_none");
imemo_type_ids[1] = rb_intern("imemo_cref");
imemo_type_ids[2] = rb_intern("imemo_svar");
imemo_type_ids[3] = rb_intern("imemo_throw_data");
imemo_type_ids[4] = rb_intern("imemo_ifunc");
imemo_type_ids[5] = rb_intern("imemo_memo");
imemo_type_ids[6] = rb_intern("imemo_ment");
imemo_type_ids[7] = rb_intern("imemo_iseq");
imemo_type_ids[8] = rb_intern("imemo_tmpbuf");
imemo_type_ids[9] = rb_intern("imemo_parser_strterm");
}
rb_objspace_each_objects(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)
{
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;
}
rb_objspace_each_objects(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_WHEN);
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_DASGN_CURR);
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_ARRAY);
COUNT_NODE(NODE_ZARRAY);
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);
#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.
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];
RVALUE *p, *pend;
p = page->start; pend = p + page->total_slots;
for (;p < pend; p++) {
if (p->as.basic.flags) {
counts[BUILTIN_TYPE(p)]++;
}
else {
freed++;
}
}
total += page->total_slots;
}
if (hash == Qnil) {
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;
switch (i) {
#define COUNT_TYPE(t) case (t): type = ID2SYM(rb_intern(#t)); break;
COUNT_TYPE(T_NONE);
COUNT_TYPE(T_OBJECT);
COUNT_TYPE(T_CLASS);
COUNT_TYPE(T_MODULE);
COUNT_TYPE(T_FLOAT);
COUNT_TYPE(T_STRING);
COUNT_TYPE(T_REGEXP);
COUNT_TYPE(T_ARRAY);
COUNT_TYPE(T_HASH);
COUNT_TYPE(T_STRUCT);
COUNT_TYPE(T_BIGNUM);
COUNT_TYPE(T_FILE);
COUNT_TYPE(T_DATA);
COUNT_TYPE(T_MATCH);
COUNT_TYPE(T_COMPLEX);
COUNT_TYPE(T_RATIONAL);
COUNT_TYPE(T_NIL);
COUNT_TYPE(T_TRUE);
COUNT_TYPE(T_FALSE);
COUNT_TYPE(T_SYMBOL);
COUNT_TYPE(T_FIXNUM);
COUNT_TYPE(T_IMEMO);
COUNT_TYPE(T_UNDEF);
COUNT_TYPE(T_ICLASS);
COUNT_TYPE(T_ZOMBIE);
#undef COUNT_TYPE
default: type = INT2NUM(i); break;
}
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.
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;
}
rb_objspace_each_objects(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();
rb_objspace_each_objects(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)
static VALUE
count_tdata_objects(int argc, VALUE *argv, VALUE self)
{
VALUE hash = setup_hash(argc, argv);
rb_objspace_each_objects(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);
should_be_finalizable(obj);
if (argc == 1) {
block = rb_block_proc();
}
else {
should_be_callable(block);
}
return define_final0(obj, block);
} Добавляет aProc в качестве финализатора, который будет вызван после уничтожения obj. Идентификатор объекта obj будет передан в качестве аргумента aProc. Если aProc является лямбда-выражением или методом, убедитесь, что его можно вызвать с одним аргументом.
static VALUE
objspace_dump(int argc, VALUE *argv, VALUE os)
{
static const char filename[] = "rubyobj";
VALUE obj = Qnil, opts = Qnil, output;
struct dump_config dc = {0,};
rb_scan_args(argc, argv, "1:", &obj, &opts);
output = dump_output(&dc, opts, sym_string, filename);
dump_object(obj, &dc);
return dump_result(&dc, output);
} Выгружает содержимое объекта Ruby как JSON.
Этот метод должен работать только с C Ruby. Это экспериментальный метод, который может быть изменен. В частности, сигнатура функции и формат вывода не гарантируется совместимость в будущих версиях Ruby.
static VALUE
objspace_dump_all(int argc, VALUE *argv, VALUE os)
{
static const char filename[] = "rubyheap";
VALUE opts = Qnil, output;
struct dump_config dc = {0,};
rb_scan_args(argc, argv, "0:", &opts);
output = dump_output(&dc, opts, sym_file, filename);
/* dump roots */
rb_objspace_reachable_objects_from_root(root_obj_i, &dc);
if (dc.roots) dump_append(&dc, "]}\n");
/* dump all objects */
rb_objspace_each_objects(heap_i, &dc);
return dump_result(&dc, output);
} Сбросить содержимое кучи Ruby как JSON.
Ожидается, что этот метод будет работать только с C Ruby. Это экспериментальный метод, который может быть изменен. В частности, сигнатура функции и формат вывода не гарантируется совместимость в будущих версиях Ruby.
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) никогда не возвращаются. В примере ниже, 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
static VALUE
gc_start_internal(int argc, VALUE *argv, VALUE self)
{
rb_objspace_t *objspace = &rb_objspace;
int reason = GPR_FLAG_FULL_MARK | GPR_FLAG_IMMEDIATE_MARK |
GPR_FLAG_IMMEDIATE_SWEEP | GPR_FLAG_METHOD;
VALUE opt = Qnil;
static ID keyword_ids[3];
rb_scan_args(argc, argv, "0:", &opt);
if (!NIL_P(opt)) {
VALUE kwvals[3];
if (!keyword_ids[0]) {
keyword_ids[0] = rb_intern("full_mark");
keyword_ids[1] = rb_intern("immediate_mark");
keyword_ids[2] = rb_intern("immediate_sweep");
}
rb_get_kwargs(opt, keyword_ids, 0, 3, kwvals);
if (kwvals[0] != Qundef && !RTEST(kwvals[0])) {
reason &= ~GPR_FLAG_FULL_MARK;
}
if (kwvals[1] != Qundef && !RTEST(kwvals[1])) {
reason &= ~GPR_FLAG_IMMEDIATE_MARK;
}
if (kwvals[2] != Qundef && !RTEST(kwvals[2])) {
reason &= ~GPR_FLAG_IMMEDIATE_SWEEP;
}
}
garbage_collect(objspace, reason);
gc_finalize_deferred(objspace);
return Qnil;
} Инициирует сбор мусора, если он не отключен вручную.
Этот метод определен с именованными аргументами, которые по умолчанию имеют значение true:
def GC.start(full_mark: true, immediate_sweep: true); end
Используйте full_mark: false для выполнения малой GC. Используйте immediate_sweep: false для отсрочки очистки (использовать ленивую очистку).
Примечание: Эти именованные аргументы зависят от реализации и версии. Не гарантируется их обратная совместимость, и они могут игнорироваться, если базовая реализация их не поддерживает.
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);
}
klass = CLASS_OF(obj);
return wrap_klass_iow(klass);
} - Специфическая функция MRI
-
Возвращает внутренний класс obj.
obj может быть экземпляром InternalObjectWrapper.
Обратите внимание, что вы не должны использовать этот метод в своем приложении.
static VALUE
objspace_internal_super_of(VALUE self, VALUE obj)
{
VALUE super;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
obj = (VALUE)DATA_PTR(obj);
}
switch (OBJ_BUILTIN_TYPE(obj)) {
case T_MODULE:
case T_CLASS:
case T_ICLASS:
super = RCLASS_SUPER(obj);
break;
default:
rb_raise(rb_eArgError, "class or module is expected");
}
return wrap_klass_iow(super);
} - Специфическая функция 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 может быть неверным.
Ожидается, что этот метод будет работать только с C Ruby.
Начиная с Ruby 2.2, memsize_of(obj) возвращает размер памяти, включая sizeof(RVALUE).
static VALUE
memsize_of_all_m(int argc, VALUE *argv, VALUE self)
{
struct total_data data = {0, 0};
if (argc > 0) {
rb_scan_args(argc, argv, "01", &data.klass);
}
rb_objspace_each_objects(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.
static VALUE
reachable_objects_from(VALUE self, VALUE obj)
{
if (rb_objspace_markable_object_p(obj)) {
VALUE ret = rb_ary_new();
struct rof_data data;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
obj = (VALUE)DATA_PTR(obj);
}
data.refs = st_init_numtable();
data.internals = rb_ary_new();
rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
st_foreach(data.refs, collect_values, (st_data_t)ret);
return ret;
}
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
static VALUE
reachable_objects_from_root(VALUE self)
{
struct rofr_data data;
VALUE hash = data.categories = rb_ident_hash_new();
data.last_category = 0;
rb_objspace_reachable_objects_from_root(reachable_object_from_root_i, &data);
rb_hash_foreach(hash, collect_values_of_values, hash);
return hash;
} - Специфическая функция MRI
-
Возвращает все доступные объекты от корня.
static VALUE
trace_object_allocations(VALUE self)
{
trace_object_allocations_start(self);
return rb_ensure(rb_yield, Qnil, trace_object_allocations_stop, self);
} Начинает трассировку выделений объектов из модуля расширения ObjectSpace.
Например:
require 'objspace'
class C
include ObjectSpace
def foo
trace_object_allocations do
obj = Object.new
p "#{allocation_sourcefile(obj)}:#{allocation_sourceline(obj)}"
end
end
end
C.new.foo #=> "objtrace.rb:8"
В этом примере включен модуль ObjectSpace, чтобы упростить чтение, но вы также можете использовать обозначение ::trace_object_allocations (рекомендуется).
Обратите внимание, что эта функция приводит к значительному снижению производительности и значительному потреблению памяти.
static VALUE
trace_object_allocations_clear(VALUE self)
{
struct traceobj_arg *arg = get_traceobj_arg();
/* clear tables */
st_foreach(arg->object_table, free_values_i, 0);
st_clear(arg->object_table);
st_foreach(arg->str_table, free_keys_i, 0);
st_clear(arg->str_table);
/* do not touch TracePoints */
return Qnil;
} Очищает записанную информацию трассировки.
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
tmp_keep_remains = 1;
if (object_allocations_reporter_registered == 0) {
object_allocations_reporter_registered = 1;
rb_bug_reporter_add(object_allocations_reporter, 0);
}
return trace_object_allocations_start(self);
} static VALUE
trace_object_allocations_start(VALUE self)
{
struct traceobj_arg *arg = get_traceobj_arg();
if (arg->running++ > 0) {
/* do nothing */
}
else {
if (arg->newobj_trace == 0) {
arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
rb_gc_register_mark_object(arg->newobj_trace);
arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
rb_gc_register_mark_object(arg->freeobj_trace);
}
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) {
rb_tracepoint_disable(arg->newobj_trace);
rb_tracepoint_disable(arg->freeobj_trace);
}
return Qnil;
} Останавливает отслеживание выделения объектов.
Обратите внимание, что если ::trace_object_allocations_start вызывается n раз, то отслеживание прекратится после вызова ::trace_object_allocations_stop n раз.
static VALUE
undefine_final(VALUE os, VALUE obj)
{
return rb_undefine_finalizer(obj);
} Удаляет все финализаторы для obj.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.