diff options
Diffstat (limited to 'ext/objspace/objspace.c')
| -rw-r--r-- | ext/objspace/objspace.c | 326 |
1 files changed, 67 insertions, 259 deletions
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index 31099b8849..457ffc2789 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -12,14 +12,13 @@ **********************************************************************/ -#include "gc.h" #include "internal.h" #include "internal/class.h" #include "internal/compilers.h" +#include "internal/gc.h" #include "internal/hash.h" #include "internal/imemo.h" #include "internal/sanitizers.h" -#include "node.h" #include "ruby/io.h" #include "ruby/re.h" #include "ruby/st.h" @@ -39,10 +38,11 @@ * information as only a *HINT*. Especially, the size of +T_DATA+ may not be * correct. * - * This method is only expected to work with C Ruby. + * This method is only expected to work with CRuby. * - * From Ruby 2.2, memsize_of(obj) returns a memory size includes - * sizeof(RVALUE). + * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot + * size used plus any additional memory allocated outside the slot (such + * as external strings, arrays, or hash tables). */ static VALUE @@ -82,15 +82,15 @@ heap_iter(void *vstart, void *vend, size_t stride, void *ptr) VALUE v; for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) { - void *poisoned = asan_poisoned_object_p(v); - asan_unpoison_object(v, false); + void *poisoned = rb_asan_poisoned_object_p(v); + rb_asan_unpoison_object(v, false); if (RBASIC(v)->flags) { (*ctx->cb)(v, ctx->data); } if (poisoned) { - asan_poison_object(v); + rb_asan_poison_object(v); } } @@ -108,28 +108,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx) /* * call-seq: - * ObjectSpace.memsize_of_all([klass]) -> Integer - * - * Return consuming memory size of all living objects in bytes. + * ObjectSpace.memsize_of_all(klass = nil) -> integer * - * If +klass+ (should be Class object) is given, return the total memory size - * of instances of the given class. + * Returns the total memory size of all living objects in bytes. * - * Note that the returned size is incomplete. You need to deal with this - * information as only a *HINT*. Especially, the size of +T_DATA+ may not be - * correct. + * ObjectSpace.memsize_of_all # => 12502001 * - * Note that this method does *NOT* return total malloc'ed memory size. + * If +klass+ is given (which must be a Class or Module), returns the total + * memory size of objects whose class is, or is a subclass, of +klass+. * - * This method can be defined by the following Ruby code: + * class MyClass; end + * ObjectSpace.memsize_of_all(MyClass) # => 0 + * o = MyClass.new + * ObjectSpace.memsize_of_all(MyClass) # => 40 * - * 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 + * Note that the value returned may be an underestimate of the actual amount + * of memory used. Therefore, the value returned should only be used as a hint, + * rather than a source of truth. In particular, the size of +T_DATA+ objects may + * not be correct. * * This method is only expected to work with C Ruby. */ @@ -170,8 +166,7 @@ setup_hash(int argc, VALUE *argv) hash = rb_hash_new(); } else if (!RHASH_EMPTY_P(hash)) { - /* WB: no new reference */ - st_foreach(RHASH_TBL_RAW(hash), set_zero_i, hash); + rb_hash_foreach(hash, set_zero_i, (st_data_t)hash); } return hash; @@ -296,28 +291,27 @@ size_t rb_sym_immortal_count(void); /* * call-seq: - * ObjectSpace.count_symbols([result_hash]) -> hash + * ObjectSpace.count_symbols(result_hash = nil) -> hash * - * Counts symbols for each Symbol type. + * Returns a hash containing the number of objects for each Symbol type. * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. + * The types of Symbols are the following: * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * - +mortal_dynamic_symbol+: Symbols that are garbage collectable. + * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the + * garbage collector, but are not garbage collectable. + * - +immortal_static_symbol+: Symbols that are not allocated from the + * garbage collector, and are thus not garbage collectable. + * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+. * - * Note: - * The contents of the returned hash is implementation defined. - * It may be changed in future. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * This method is only expected to work with C Ruby. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * - * On this version of MRI, they have 3 types of Symbols (and 1 total counts). - * - * * 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) + * This method is only expected to work with C Ruby. */ static VALUE @@ -338,174 +332,6 @@ count_symbols(int argc, VALUE *argv, VALUE os) } static void -cn_i(VALUE v, void *n) -{ - size_t *nodes = (size_t *)n; - - if (BUILTIN_TYPE(v) == T_NODE) { - size_t s = nd_type((NODE *)v); - nodes[s]++; - } -} - -/* - * call-seq: - * ObjectSpace.count_nodes([result_hash]) -> hash - * - * Counts nodes for each node type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. - * - * It returns a hash as: - * - * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...} - * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. - * - * Note: - * The contents of the returned hash is implementation defined. - * It may be changed in future. - * - * This method is only expected to work with 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; - } - - 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; -} - -static void cto_i(VALUE v, void *data) { VALUE hash = (VALUE)data; @@ -534,32 +360,22 @@ cto_i(VALUE v, void *data) /* * call-seq: - * ObjectSpace.count_tdata_objects([result_hash]) -> hash - * - * Counts objects for each +T_DATA+ type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. - * - * It returns a hash as: + * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash * - * {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. + * Returns a hash containing the number of objects for each +T_DATA+ type. + * The keys are Class objects when the +T_DATA+ object has an associated class, + * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal + * +T_DATA+ objects. * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * ObjectSpace.count_tdata_objects + * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... } * - * The contents of the returned hash is implementation specific and may change - * in the future. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * In this version, keys are Class object or Symbol object. - * - * If object is kind of normal (accessible) object, the key is Class object. - * If object is not a kind of normal (internal) object, the key is symbol - * name, registered by rb_data_type_struct. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * * This method is only expected to work with C Ruby. */ @@ -598,28 +414,22 @@ count_imemo_objects_i(VALUE v, void *data) /* * call-seq: - * ObjectSpace.count_imemo_objects([result_hash]) -> hash - * - * Counts objects for each +T_IMEMO+ type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. + * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash * - * It returns a hash as: - * - * {:imemo_ifunc=>8, - * :imemo_svar=>7, - * :imemo_cref=>509, - * :imemo_memo=>1, - * :imemo_throw_data=>1} + * Returns a hash containing the number of objects for each +T_IMEMO+ type. + * The keys are Symbol objects of the +T_IMEMO+ type name. + * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby + * programs. * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * ObjectSpace.count_imemo_objects + * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... } * - * The contents of the returned hash is implementation specific and may change - * in the future. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * In this version, keys are symbol objects. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * * This method is only expected to work with C Ruby. */ @@ -640,11 +450,10 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self) 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); + INIT_IMEMO_TYPE_ID(imemo_fields); #undef INIT_IMEMO_TYPE_ID } @@ -718,7 +527,7 @@ reachable_object_from_i(VALUE obj, void *data_ptr) VALUE key = obj; VALUE val = obj; - if (rb_objspace_markable_object_p(obj)) { + if (!rb_objspace_garbage_object_p(obj)) { if (NIL_P(rb_hash_lookup(data->refs, key))) { rb_hash_aset(data->refs, key, Qtrue); @@ -764,7 +573,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data) * * With this method, you can find memory leaks. * - * This method is only expected to work except with C Ruby. + * This method is only expected to work with C Ruby. * * Example: * ObjectSpace.reachable_objects_from(['a', 'b', 'c']) @@ -784,7 +593,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data) static VALUE reachable_objects_from(VALUE self, VALUE obj) { - if (rb_objspace_markable_object_p(obj)) { + if (!RB_SPECIAL_CONST_P(obj)) { struct rof_data data; if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { @@ -831,7 +640,7 @@ reachable_object_from_root_i(const char *category, VALUE obj, void *ptr) rb_hash_aset(data->categories, category_str, category_objects); } - if (rb_objspace_markable_object_p(obj) && + if (!rb_objspace_garbage_object_p(obj) && obj != data->categories && obj != data->last_category_objects) { if (rb_objspace_internal_object_p(obj)) { @@ -933,7 +742,7 @@ objspace_internal_super_of(VALUE self, VALUE obj) case T_MODULE: case T_CLASS: case T_ICLASS: - super = RCLASS_SUPER(obj); + super = rb_class_super_of(obj); break; default: rb_raise(rb_eArgError, "class or module is expected"); @@ -975,7 +784,6 @@ Init_objspace(void) rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1); rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1); - rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1); rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1); rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1); |
