Ruby 1.9.3p327(2012-11-10revision37606)
ext/objspace/objspace.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   objspace.c - ObjectSpace extender for MRI.
00004 
00005   $Author: ktsj $
00006   created at: Wed Jun 17 07:39:17 2009
00007 
00008   NOTE: This extension library is not expected to exist except C Ruby.
00009 
00010   All the files in this distribution are covered under the Ruby's
00011   license (see the file COPYING).
00012 
00013 **********************************************************************/
00014 
00015 /* objspace library extends ObjectSpace module and add several
00016  * methods to get internal statistic information about
00017  * object/memory management.
00018  *
00019  * Generally, you *SHOULD NOT*use this library if you do not know
00020  * about the MRI implementation.  Mainly, this library is for (memory)
00021  * profiler developers and MRI developers who need to know how MRI
00022  * memory usage.
00023  *
00024  */
00025 
00026 #include <ruby/ruby.h>
00027 #include <ruby/st.h>
00028 #include <ruby/io.h>
00029 #include <ruby/re.h>
00030 #include "node.h"
00031 #include "gc.h"
00032 #include "regint.h"
00033 #include "internal.h"
00034 
00035 size_t rb_str_memsize(VALUE);
00036 size_t rb_ary_memsize(VALUE);
00037 size_t rb_io_memsize(const rb_io_t *);
00038 size_t rb_generic_ivar_memsize(VALUE);
00039 size_t rb_objspace_data_type_memsize(VALUE obj);
00040 
00041 static size_t
00042 memsize_of(VALUE obj)
00043 {
00044     size_t size = 0;
00045 
00046     if (SPECIAL_CONST_P(obj)) {
00047         return 0;
00048     }
00049 
00050     if (FL_TEST(obj, FL_EXIVAR)) {
00051         size += rb_generic_ivar_memsize(obj);
00052     }
00053 
00054     switch (BUILTIN_TYPE(obj)) {
00055       case T_OBJECT:
00056         if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
00057             ROBJECT(obj)->as.heap.ivptr) {
00058             size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
00059         }
00060         break;
00061       case T_MODULE:
00062       case T_CLASS:
00063         size += st_memsize(RCLASS_M_TBL(obj));
00064         if (RCLASS_IV_TBL(obj)) {
00065             size += st_memsize(RCLASS_IV_TBL(obj));
00066         }
00067         if (RCLASS_IV_INDEX_TBL(obj)) {
00068             size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
00069         }
00070         if (RCLASS(obj)->ptr->iv_tbl) {
00071             size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
00072         }
00073         if (RCLASS(obj)->ptr->const_tbl) {
00074             size += st_memsize(RCLASS(obj)->ptr->const_tbl);
00075         }
00076         size += sizeof(rb_classext_t);
00077         break;
00078       case T_STRING:
00079         size += rb_str_memsize(obj);
00080         break;
00081       case T_ARRAY:
00082         size += rb_ary_memsize(obj);
00083         break;
00084       case T_HASH:
00085         if (RHASH(obj)->ntbl) {
00086             size += st_memsize(RHASH(obj)->ntbl);
00087         }
00088         break;
00089       case T_REGEXP:
00090         if (RREGEXP(obj)->ptr) {
00091             size += onig_memsize(RREGEXP(obj)->ptr);
00092         }
00093         break;
00094       case T_DATA:
00095         size += rb_objspace_data_type_memsize(obj);
00096         break;
00097       case T_MATCH:
00098         if (RMATCH(obj)->rmatch) {
00099             struct rmatch *rm = RMATCH(obj)->rmatch;
00100             size += sizeof(struct re_registers); /* TODO: onig_region_memsize(&rm->regs); */
00101             size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
00102             size += sizeof(struct rmatch);
00103         }
00104         break;
00105       case T_FILE:
00106         if (RFILE(obj)->fptr) {
00107             size += rb_io_memsize(RFILE(obj)->fptr);
00108         }
00109         break;
00110       case T_RATIONAL:
00111       case T_COMPLEX:
00112         break;
00113       case T_ICLASS:
00114         /* iClass shares table with the module */
00115         break;
00116 
00117       case T_FLOAT:
00118         break;
00119 
00120       case T_BIGNUM:
00121         if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
00122             size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
00123         }
00124         break;
00125       case T_NODE:
00126         switch (nd_type(obj)) {
00127           case NODE_SCOPE:
00128             if (RNODE(obj)->u1.tbl) {
00129                 /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */
00130             }
00131             break;
00132           case NODE_ALLOCA:
00133             /* TODO: xfree(RANY(obj)->as.node.u1.node); */
00134             ;
00135         }
00136         break;                  /* no need to free iv_tbl */
00137 
00138       case T_STRUCT:
00139         if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
00140             RSTRUCT(obj)->as.heap.ptr) {
00141             size += sizeof(VALUE) * RSTRUCT_LEN(obj);
00142         }
00143         break;
00144 
00145       case T_ZOMBIE:
00146         break;
00147 
00148       default:
00149         rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
00150                BUILTIN_TYPE(obj), (void*)obj);
00151     }
00152 
00153     return size;
00154 }
00155 
00156 /*
00157  *  call-seq:
00158  *    ObjectSpace.memsize_of(obj) -> Integer
00159  *
00160  *  Return consuming memory size of obj.
00161  *
00162  *  Note that the return size is incomplete.  You need to deal with
00163  *  this information as only a *HINT*.  Especially, the size of
00164  *  T_DATA may not be correct.
00165  *
00166  *  This method is not expected to work except C Ruby.
00167  */
00168 
00169 static VALUE
00170 memsize_of_m(VALUE self, VALUE obj)
00171 {
00172     return SIZET2NUM(memsize_of(obj));
00173 }
00174 
00175 struct total_data {
00176     size_t total;
00177     VALUE klass;
00178 };
00179 
00180 static int
00181 total_i(void *vstart, void *vend, size_t stride, void *ptr)
00182 {
00183     VALUE v;
00184     struct total_data *data = (struct total_data *)ptr;
00185 
00186     for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
00187         if (RBASIC(v)->flags) {
00188             switch (BUILTIN_TYPE(v)) {
00189               case T_NONE:
00190               case T_ICLASS:
00191               case T_NODE:
00192               case T_ZOMBIE:
00193                 continue;
00194               case T_CLASS:
00195                 if (FL_TEST(v, FL_SINGLETON))
00196                   continue;
00197               default:
00198                 if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
00199                     data->total += memsize_of(v);
00200                 }
00201             }
00202         }
00203     }
00204 
00205     return 0;
00206 }
00207 
00208 /*
00209  *  call-seq:
00210  *    ObjectSpace.memsize_of_all([klass]) -> Integer
00211  *
00212  *  Return consuming memory size of all living objects.
00213  *  If klass (should be Class object) is given, return the total
00214  *  memory size of instances of the given class.
00215  *
00216  *  Note that the returned size is incomplete.  You need to deal with
00217  *  this information as only a *HINT*.  Especially, the size of
00218  *  T_DATA may not be correct.
00219  *
00220  *  Note that this method does *NOT* return total malloc'ed memory size.
00221  *
00222  *  This method can be defined by the following Ruby code:
00223  *
00224  *  def memsize_of_all klass = false
00225  *    total = 0
00226  *    ObjectSpace.each_objects{|e|
00227  *      total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
00228  *    }
00229  *    total
00230  *  end
00231  *
00232  *  This method is not expected to work except C Ruby.
00233  */
00234 
00235 static VALUE
00236 memsize_of_all_m(int argc, VALUE *argv, VALUE self)
00237 {
00238     struct total_data data = {0, 0};
00239 
00240     if (argc > 0) {
00241         rb_scan_args(argc, argv, "01", &data.klass);
00242     }
00243 
00244     rb_objspace_each_objects(total_i, &data);
00245     return SIZET2NUM(data.total);
00246 }
00247 
00248 static int
00249 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
00250 {
00251     VALUE k = (VALUE)key;
00252     VALUE hash = (VALUE)arg;
00253     rb_hash_aset(hash, k, INT2FIX(0));
00254     return ST_CONTINUE;
00255 }
00256 
00257 static int
00258 cos_i(void *vstart, void *vend, size_t stride, void *data)
00259 {
00260     size_t *counts = (size_t *)data;
00261     VALUE v = (VALUE)vstart;
00262 
00263     for (;v != (VALUE)vend; v += stride) {
00264         if (RBASIC(v)->flags) {
00265             counts[BUILTIN_TYPE(v)] += memsize_of(v);
00266         }
00267     }
00268     return 0;
00269 }
00270 
00271 /*
00272  *  call-seq:
00273  *    ObjectSpace.count_objects_size([result_hash]) -> hash
00274  *
00275  *  Counts objects size (in bytes) for each type.
00276  *
00277  *  Note that this information is incomplete.  You need to deal with
00278  *  this information as only a *HINT*.  Especially, total size of
00279  *  T_DATA may not right size.
00280  *
00281  *  It returns a hash as:
00282  *    {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
00283  *
00284  *  If the optional argument, result_hash, is given,
00285  *  it is overwritten and returned.
00286  *  This is intended to avoid probe effect.
00287  *
00288  *  The contents of the returned hash is implementation defined.
00289  *  It may be changed in future.
00290  *
00291  *  This method is not expected to work except C Ruby.
00292  */
00293 
00294 static VALUE
00295 count_objects_size(int argc, VALUE *argv, VALUE os)
00296 {
00297     size_t counts[T_MASK+1];
00298     size_t total = 0;
00299     size_t i;
00300     VALUE hash;
00301 
00302     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00303         if (TYPE(hash) != T_HASH)
00304             rb_raise(rb_eTypeError, "non-hash given");
00305     }
00306 
00307     for (i = 0; i <= T_MASK; i++) {
00308         counts[i] = 0;
00309     }
00310 
00311     rb_objspace_each_objects(cos_i, &counts[0]);
00312 
00313     if (hash == Qnil) {
00314         hash = rb_hash_new();
00315     }
00316     else if (!RHASH_EMPTY_P(hash)) {
00317         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00318     }
00319 
00320     for (i = 0; i <= T_MASK; i++) {
00321         if (counts[i]) {
00322             VALUE type;
00323             switch (i) {
00324 #define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
00325                 COUNT_TYPE(T_NONE);
00326                 COUNT_TYPE(T_OBJECT);
00327                 COUNT_TYPE(T_CLASS);
00328                 COUNT_TYPE(T_MODULE);
00329                 COUNT_TYPE(T_FLOAT);
00330                 COUNT_TYPE(T_STRING);
00331                 COUNT_TYPE(T_REGEXP);
00332                 COUNT_TYPE(T_ARRAY);
00333                 COUNT_TYPE(T_HASH);
00334                 COUNT_TYPE(T_STRUCT);
00335                 COUNT_TYPE(T_BIGNUM);
00336                 COUNT_TYPE(T_FILE);
00337                 COUNT_TYPE(T_DATA);
00338                 COUNT_TYPE(T_MATCH);
00339                 COUNT_TYPE(T_COMPLEX);
00340                 COUNT_TYPE(T_RATIONAL);
00341                 COUNT_TYPE(T_NIL);
00342                 COUNT_TYPE(T_TRUE);
00343                 COUNT_TYPE(T_FALSE);
00344                 COUNT_TYPE(T_SYMBOL);
00345                 COUNT_TYPE(T_FIXNUM);
00346                 COUNT_TYPE(T_UNDEF);
00347                 COUNT_TYPE(T_NODE);
00348                 COUNT_TYPE(T_ICLASS);
00349                 COUNT_TYPE(T_ZOMBIE);
00350 #undef COUNT_TYPE
00351               default: type = INT2NUM(i); break;
00352             }
00353             total += counts[i];
00354             rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
00355         }
00356     }
00357     rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
00358     return hash;
00359 }
00360 
00361 static int
00362 cn_i(void *vstart, void *vend, size_t stride, void *n)
00363 {
00364     size_t *nodes = (size_t *)n;
00365     VALUE v = (VALUE)vstart;
00366 
00367     for (; v != (VALUE)vend; v += stride) {
00368         if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
00369             size_t s = nd_type((NODE *)v);
00370             nodes[s]++;
00371         }
00372     }
00373 
00374     return 0;
00375 }
00376 
00377 /*
00378  *  call-seq:
00379  *     ObjectSpace.count_nodes([result_hash]) -> hash
00380  *
00381  *  Counts nodes for each node type.
00382  *
00383  *  This method is not for ordinary Ruby programmers, but for MRI developers
00384  *  who have interest in MRI performance and memory usage.
00385  *
00386  *  It returns a hash as:
00387  *  {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
00388  *
00389  *  If the optional argument, result_hash, is given,
00390  *  it is overwritten and returned.
00391  *  This is intended to avoid probe effect.
00392  *
00393  *  The contents of the returned hash is implementation defined.
00394  *  It may be changed in future.
00395  *
00396  *  This method is not expected to work except C Ruby.
00397  */
00398 
00399 static VALUE
00400 count_nodes(int argc, VALUE *argv, VALUE os)
00401 {
00402     size_t nodes[NODE_LAST+1];
00403     size_t i;
00404     VALUE hash;
00405 
00406     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00407         if (TYPE(hash) != T_HASH)
00408             rb_raise(rb_eTypeError, "non-hash given");
00409     }
00410 
00411     for (i = 0; i <= NODE_LAST; i++) {
00412         nodes[i] = 0;
00413     }
00414 
00415     rb_objspace_each_objects(cn_i, &nodes[0]);
00416 
00417     if (hash == Qnil) {
00418         hash = rb_hash_new();
00419     }
00420     else if (!RHASH_EMPTY_P(hash)) {
00421         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00422     }
00423 
00424     for (i=0; i<NODE_LAST; i++) {
00425         if (nodes[i] != 0) {
00426             VALUE node;
00427             switch (i) {
00428 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
00429                 COUNT_NODE(NODE_SCOPE);
00430                 COUNT_NODE(NODE_BLOCK);
00431                 COUNT_NODE(NODE_IF);
00432                 COUNT_NODE(NODE_CASE);
00433                 COUNT_NODE(NODE_WHEN);
00434                 COUNT_NODE(NODE_OPT_N);
00435                 COUNT_NODE(NODE_WHILE);
00436                 COUNT_NODE(NODE_UNTIL);
00437                 COUNT_NODE(NODE_ITER);
00438                 COUNT_NODE(NODE_FOR);
00439                 COUNT_NODE(NODE_BREAK);
00440                 COUNT_NODE(NODE_NEXT);
00441                 COUNT_NODE(NODE_REDO);
00442                 COUNT_NODE(NODE_RETRY);
00443                 COUNT_NODE(NODE_BEGIN);
00444                 COUNT_NODE(NODE_RESCUE);
00445                 COUNT_NODE(NODE_RESBODY);
00446                 COUNT_NODE(NODE_ENSURE);
00447                 COUNT_NODE(NODE_AND);
00448                 COUNT_NODE(NODE_OR);
00449                 COUNT_NODE(NODE_MASGN);
00450                 COUNT_NODE(NODE_LASGN);
00451                 COUNT_NODE(NODE_DASGN);
00452                 COUNT_NODE(NODE_DASGN_CURR);
00453                 COUNT_NODE(NODE_GASGN);
00454                 COUNT_NODE(NODE_IASGN);
00455                 COUNT_NODE(NODE_IASGN2);
00456                 COUNT_NODE(NODE_CDECL);
00457                 COUNT_NODE(NODE_CVASGN);
00458                 COUNT_NODE(NODE_CVDECL);
00459                 COUNT_NODE(NODE_OP_ASGN1);
00460                 COUNT_NODE(NODE_OP_ASGN2);
00461                 COUNT_NODE(NODE_OP_ASGN_AND);
00462                 COUNT_NODE(NODE_OP_ASGN_OR);
00463                 COUNT_NODE(NODE_CALL);
00464                 COUNT_NODE(NODE_FCALL);
00465                 COUNT_NODE(NODE_VCALL);
00466                 COUNT_NODE(NODE_SUPER);
00467                 COUNT_NODE(NODE_ZSUPER);
00468                 COUNT_NODE(NODE_ARRAY);
00469                 COUNT_NODE(NODE_ZARRAY);
00470                 COUNT_NODE(NODE_VALUES);
00471                 COUNT_NODE(NODE_HASH);
00472                 COUNT_NODE(NODE_RETURN);
00473                 COUNT_NODE(NODE_YIELD);
00474                 COUNT_NODE(NODE_LVAR);
00475                 COUNT_NODE(NODE_DVAR);
00476                 COUNT_NODE(NODE_GVAR);
00477                 COUNT_NODE(NODE_IVAR);
00478                 COUNT_NODE(NODE_CONST);
00479                 COUNT_NODE(NODE_CVAR);
00480                 COUNT_NODE(NODE_NTH_REF);
00481                 COUNT_NODE(NODE_BACK_REF);
00482                 COUNT_NODE(NODE_MATCH);
00483                 COUNT_NODE(NODE_MATCH2);
00484                 COUNT_NODE(NODE_MATCH3);
00485                 COUNT_NODE(NODE_LIT);
00486                 COUNT_NODE(NODE_STR);
00487                 COUNT_NODE(NODE_DSTR);
00488                 COUNT_NODE(NODE_XSTR);
00489                 COUNT_NODE(NODE_DXSTR);
00490                 COUNT_NODE(NODE_EVSTR);
00491                 COUNT_NODE(NODE_DREGX);
00492                 COUNT_NODE(NODE_DREGX_ONCE);
00493                 COUNT_NODE(NODE_ARGS);
00494                 COUNT_NODE(NODE_ARGS_AUX);
00495                 COUNT_NODE(NODE_OPT_ARG);
00496                 COUNT_NODE(NODE_POSTARG);
00497                 COUNT_NODE(NODE_ARGSCAT);
00498                 COUNT_NODE(NODE_ARGSPUSH);
00499                 COUNT_NODE(NODE_SPLAT);
00500                 COUNT_NODE(NODE_TO_ARY);
00501                 COUNT_NODE(NODE_BLOCK_ARG);
00502                 COUNT_NODE(NODE_BLOCK_PASS);
00503                 COUNT_NODE(NODE_DEFN);
00504                 COUNT_NODE(NODE_DEFS);
00505                 COUNT_NODE(NODE_ALIAS);
00506                 COUNT_NODE(NODE_VALIAS);
00507                 COUNT_NODE(NODE_UNDEF);
00508                 COUNT_NODE(NODE_CLASS);
00509                 COUNT_NODE(NODE_MODULE);
00510                 COUNT_NODE(NODE_SCLASS);
00511                 COUNT_NODE(NODE_COLON2);
00512                 COUNT_NODE(NODE_COLON3);
00513                 COUNT_NODE(NODE_DOT2);
00514                 COUNT_NODE(NODE_DOT3);
00515                 COUNT_NODE(NODE_FLIP2);
00516                 COUNT_NODE(NODE_FLIP3);
00517                 COUNT_NODE(NODE_SELF);
00518                 COUNT_NODE(NODE_NIL);
00519                 COUNT_NODE(NODE_TRUE);
00520                 COUNT_NODE(NODE_FALSE);
00521                 COUNT_NODE(NODE_ERRINFO);
00522                 COUNT_NODE(NODE_DEFINED);
00523                 COUNT_NODE(NODE_POSTEXE);
00524                 COUNT_NODE(NODE_ALLOCA);
00525                 COUNT_NODE(NODE_BMETHOD);
00526                 COUNT_NODE(NODE_MEMO);
00527                 COUNT_NODE(NODE_IFUNC);
00528                 COUNT_NODE(NODE_DSYM);
00529                 COUNT_NODE(NODE_ATTRASGN);
00530                 COUNT_NODE(NODE_PRELUDE);
00531                 COUNT_NODE(NODE_LAMBDA);
00532                 COUNT_NODE(NODE_OPTBLOCK);
00533 #undef COUNT_NODE
00534               default: node = INT2FIX(nodes[i]);
00535             }
00536             rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
00537         }
00538     }
00539     return hash;
00540 }
00541 
00542 static int
00543 cto_i(void *vstart, void *vend, size_t stride, void *data)
00544 {
00545     VALUE hash = (VALUE)data;
00546     VALUE v = (VALUE)vstart;
00547 
00548     for (; v != (VALUE)vend; v += stride) {
00549         if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
00550             VALUE counter;
00551             VALUE key = RBASIC(v)->klass;
00552 
00553             if (key == 0) {
00554                 const char *name = rb_objspace_data_type_name(v);
00555                 if (name == 0) name = "unknown";
00556                 key = ID2SYM(rb_intern(name));
00557             }
00558 
00559             counter = rb_hash_aref(hash, key);
00560             if (NIL_P(counter)) {
00561                 counter = INT2FIX(1);
00562             }
00563             else {
00564                 counter = INT2FIX(FIX2INT(counter) + 1);
00565             }
00566 
00567             rb_hash_aset(hash, key, counter);
00568         }
00569     }
00570 
00571     return 0;
00572 }
00573 
00574 /*
00575  *  call-seq:
00576  *     ObjectSpace.count_tdata_objects([result_hash]) -> hash
00577  *
00578  *  Counts objects for each T_DATA type.
00579  *
00580  *  This method is not for ordinary Ruby programmers, but for MRI developers
00581  *  who interest on MRI performance.
00582  *
00583  *  It returns a hash as:
00584  *  {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
00585  *   :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
00586  *   ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
00587  *   Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
00588  *  # T_DATA objects existing at startup on r32276.
00589  *
00590  *  If the optional argument, result_hash, is given,
00591  *  it is overwritten and returned.
00592  *  This is intended to avoid probe effect.
00593  *
00594  *  The contents of the returned hash is implementation defined.
00595  *  It may be changed in future.
00596  *
00597  *  In this version, keys are Class object or Symbol object.
00598  *  If object is kind of normal (accessible) object, the key is Class object.
00599  *  If object is not a kind of normal (internal) object, the key is symbol
00600  *  name, registered by rb_data_type_struct.
00601  *
00602  *  This method is not expected to work except C Ruby.
00603  *
00604  */
00605 
00606 static VALUE
00607 count_tdata_objects(int argc, VALUE *argv, VALUE self)
00608 {
00609     VALUE hash;
00610 
00611     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
00612         if (TYPE(hash) != T_HASH)
00613             rb_raise(rb_eTypeError, "non-hash given");
00614     }
00615 
00616     if (hash == Qnil) {
00617         hash = rb_hash_new();
00618     }
00619     else if (!RHASH_EMPTY_P(hash)) {
00620         st_foreach(RHASH_TBL(hash), set_zero_i, hash);
00621     }
00622 
00623     rb_objspace_each_objects(cto_i, (void *)hash);
00624 
00625     return hash;
00626 }
00627 
00628 /* objspace library extends ObjectSpace module and add several
00629  * methods to get internal statistic information about
00630  * object/memory management.
00631  *
00632  * Generally, you *SHOULD NOT*use this library if you do not know
00633  * about the MRI implementation.  Mainly, this library is for (memory)
00634  * profiler developers and MRI developers who need to know how MRI
00635  * memory usage.
00636  */
00637 
00638 void
00639 Init_objspace(void)
00640 {
00641     VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
00642 
00643     rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
00644     rb_define_module_function(rb_mObjSpace, "memsize_of_all",
00645                               memsize_of_all_m, -1);
00646 
00647     rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
00648     rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
00649     rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
00650 }
00651