Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

objspace.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 objspace.c - ObjectSpace extender for MRI.
4
5 $Author: nagachika $
6 created at: Wed Jun 17 07:39:17 2009
7
8 NOTE: This extension library is not expected to exist except C Ruby.
9
10 All the files in this distribution are covered under the Ruby's
11 license (see the file COPYING).
12
13 **********************************************************************/
14
15 /* objspace library extends ObjectSpace module and add several
16 * methods to get internal statistic information about
17 * object/memory management.
18 *
19 * Generally, you *SHOULD NOT*use this library if you do not know
20 * about the MRI implementation. Mainly, this library is for (memory)
21 * profiler developers and MRI developers who need to know how MRI
22 * memory usage.
23 *
24 */
25
26 #include <ruby/ruby.h>
27 #include <ruby/st.h>
28 #include <ruby/io.h>
29 #include <ruby/re.h>
30 #include "node.h"
31 #include "gc.h"
32 #include "regint.h"
33 #include "internal.h"
34
35 size_t rb_str_memsize(VALUE);
36 size_t rb_ary_memsize(VALUE);
37 size_t rb_io_memsize(const rb_io_t *);
38 size_t rb_generic_ivar_memsize(VALUE);
39 size_t rb_objspace_data_type_memsize(VALUE obj);
40
41 static size_t
42 memsize_of(VALUE obj)
43 {
44 size_t size = 0;
45
46 if (SPECIAL_CONST_P(obj)) {
47 return 0;
48 }
49
50 if (FL_TEST(obj, FL_EXIVAR)) {
51 size += rb_generic_ivar_memsize(obj);
52 }
53
54 switch (BUILTIN_TYPE(obj)) {
55 case T_OBJECT:
56 if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
57 ROBJECT(obj)->as.heap.ivptr) {
58 size += ROBJECT(obj)->as.heap.numiv * sizeof(VALUE);
59 }
60 break;
61 case T_MODULE:
62 case T_CLASS:
63 if (RCLASS_M_TBL(obj)) {
64 size += st_memsize(RCLASS_M_TBL(obj));
65 }
66 if (RCLASS_IV_TBL(obj)) {
67 size += st_memsize(RCLASS_IV_TBL(obj));
68 }
69 if (RCLASS_IV_INDEX_TBL(obj)) {
70 size += st_memsize(RCLASS_IV_INDEX_TBL(obj));
71 }
72 if (RCLASS(obj)->ptr->iv_tbl) {
73 size += st_memsize(RCLASS(obj)->ptr->iv_tbl);
74 }
75 if (RCLASS(obj)->ptr->const_tbl) {
76 size += st_memsize(RCLASS(obj)->ptr->const_tbl);
77 }
78 size += sizeof(rb_classext_t);
79 break;
80 case T_STRING:
81 size += rb_str_memsize(obj);
82 break;
83 case T_ARRAY:
84 size += rb_ary_memsize(obj);
85 break;
86 case T_HASH:
87 if (RHASH(obj)->ntbl) {
88 size += st_memsize(RHASH(obj)->ntbl);
89 }
90 break;
91 case T_REGEXP:
92 if (RREGEXP(obj)->ptr) {
93 size += onig_memsize(RREGEXP(obj)->ptr);
94 }
95 break;
96 case T_DATA:
97 size += rb_objspace_data_type_memsize(obj);
98 break;
99 case T_MATCH:
100 if (RMATCH(obj)->rmatch) {
101 struct rmatch *rm = RMATCH(obj)->rmatch;
102 size += onig_region_memsize(&rm->regs);
103 size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
104 size += sizeof(struct rmatch);
105 }
106 break;
107 case T_FILE:
108 if (RFILE(obj)->fptr) {
109 size += rb_io_memsize(RFILE(obj)->fptr);
110 }
111 break;
112 case T_RATIONAL:
113 case T_COMPLEX:
114 break;
115 case T_ICLASS:
116 /* iClass shares table with the module */
117 break;
118
119 case T_FLOAT:
120 break;
121
122 case T_BIGNUM:
123 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
124 size += RBIGNUM_LEN(obj) * sizeof(BDIGIT);
125 }
126 break;
127 case T_NODE:
128 switch (nd_type(obj)) {
129 case NODE_SCOPE:
130 if (RNODE(obj)->u1.tbl) {
131 /* TODO: xfree(RANY(obj)->as.node.u1.tbl); */
132 }
133 break;
134 case NODE_ALLOCA:
135 /* TODO: xfree(RANY(obj)->as.node.u1.node); */
136 ;
137 }
138 break; /* no need to free iv_tbl */
139
140 case T_STRUCT:
141 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
142 RSTRUCT(obj)->as.heap.ptr) {
143 size += sizeof(VALUE) * RSTRUCT_LEN(obj);
144 }
145 break;
146
147 case T_ZOMBIE:
148 break;
149
150 default:
151 rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
152 BUILTIN_TYPE(obj), (void*)obj);
153 }
154
155 return size;
156 }
157
158 /*
159 * call-seq:
160 * ObjectSpace.memsize_of(obj) -> Integer
161 *
162 * Return consuming memory size of obj.
163 *
164 * Note that the return size is incomplete. You need to deal with
165 * this information as only a *HINT*. Especially, the size of
166 * T_DATA may not be correct.
167 *
168 * This method is not expected to work except C Ruby.
169 */
170
171 static VALUE
172 memsize_of_m(VALUE self, VALUE obj)
173 {
174 return SIZET2NUM(memsize_of(obj));
175 }
176
177 struct total_data {
178 size_t total;
179 VALUE klass;
180 };
181
182 static int
183 total_i(void *vstart, void *vend, size_t stride, void *ptr)
184 {
185 VALUE v;
186 struct total_data *data = (struct total_data *)ptr;
187
188 for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
189 if (RBASIC(v)->flags) {
190 switch (BUILTIN_TYPE(v)) {
191 case T_NONE:
192 case T_ICLASS:
193 case T_NODE:
194 case T_ZOMBIE:
195 continue;
196 case T_CLASS:
197 if (FL_TEST(v, FL_SINGLETON))
198 continue;
199 default:
200 if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
201 data->total += memsize_of(v);
202 }
203 }
204 }
205 }
206
207 return 0;
208 }
209
210 /*
211 * call-seq:
212 * ObjectSpace.memsize_of_all([klass]) -> Integer
213 *
214 * Return consuming memory size of all living objects.
215 * If klass (should be Class object) is given, return the total
216 * memory size of instances of the given class.
217 *
218 * Note that the returned size is incomplete. You need to deal with
219 * this information as only a *HINT*. Especially, the size of
220 * T_DATA may not be correct.
221 *
222 * Note that this method does *NOT* return total malloc'ed memory size.
223 *
224 * This method can be defined by the following Ruby code:
225 *
226 * def memsize_of_all klass = false
227 * total = 0
228 * ObjectSpace.each_object{|e|
229 * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
230 * }
231 * total
232 * end
233 *
234 * This method is not expected to work except C Ruby.
235 */
236
237 static VALUE
238 memsize_of_all_m(int argc, VALUE *argv, VALUE self)
239 {
240 struct total_data data = {0, 0};
241
242 if (argc > 0) {
243 rb_scan_args(argc, argv, "01", &data.klass);
244 }
245
246 rb_objspace_each_objects(total_i, &data);
247 return SIZET2NUM(data.total);
248 }
249
250 static int
251 set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
252 {
253 VALUE k = (VALUE)key;
254 VALUE hash = (VALUE)arg;
255 rb_hash_aset(hash, k, INT2FIX(0));
256 return ST_CONTINUE;
257 }
258
259 static int
260 cos_i(void *vstart, void *vend, size_t stride, void *data)
261 {
262 size_t *counts = (size_t *)data;
263 VALUE v = (VALUE)vstart;
264
265 for (;v != (VALUE)vend; v += stride) {
266 if (RBASIC(v)->flags) {
267 counts[BUILTIN_TYPE(v)] += memsize_of(v);
268 }
269 }
270 return 0;
271 }
272
273 static VALUE
274 type2sym(enum ruby_value_type i)
275 {
276 VALUE type;
277 switch (i) {
278 #define CASE_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
279 CASE_TYPE(T_NONE);
280 CASE_TYPE(T_OBJECT);
281 CASE_TYPE(T_CLASS);
282 CASE_TYPE(T_MODULE);
283 CASE_TYPE(T_FLOAT);
284 CASE_TYPE(T_STRING);
285 CASE_TYPE(T_REGEXP);
286 CASE_TYPE(T_ARRAY);
287 CASE_TYPE(T_HASH);
288 CASE_TYPE(T_STRUCT);
289 CASE_TYPE(T_BIGNUM);
290 CASE_TYPE(T_FILE);
291 CASE_TYPE(T_DATA);
292 CASE_TYPE(T_MATCH);
293 CASE_TYPE(T_COMPLEX);
294 CASE_TYPE(T_RATIONAL);
295 CASE_TYPE(T_NIL);
296 CASE_TYPE(T_TRUE);
297 CASE_TYPE(T_FALSE);
298 CASE_TYPE(T_SYMBOL);
299 CASE_TYPE(T_FIXNUM);
300 CASE_TYPE(T_UNDEF);
301 CASE_TYPE(T_NODE);
302 CASE_TYPE(T_ICLASS);
303 CASE_TYPE(T_ZOMBIE);
304 #undef CASE_TYPE
305 default: rb_bug("type2sym: unknown type (%d)", i);
306 }
307 return type;
308 }
309
310 /*
311 * call-seq:
312 * ObjectSpace.count_objects_size([result_hash]) -> hash
313 *
314 * Counts objects size (in bytes) for each type.
315 *
316 * Note that this information is incomplete. You need to deal with
317 * this information as only a *HINT*. Especially, total size of
318 * T_DATA may not right size.
319 *
320 * It returns a hash as:
321 * {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...}
322 *
323 * If the optional argument, result_hash, is given,
324 * it is overwritten and returned.
325 * This is intended to avoid probe effect.
326 *
327 * The contents of the returned hash is implementation defined.
328 * It may be changed in future.
329 *
330 * This method is not expected to work except C Ruby.
331 */
332
333 static VALUE
334 count_objects_size(int argc, VALUE *argv, VALUE os)
335 {
336 size_t counts[T_MASK+1];
337 size_t total = 0;
338 enum ruby_value_type i;
339 VALUE hash;
340
341 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
342 if (!RB_TYPE_P(hash, T_HASH))
343 rb_raise(rb_eTypeError, "non-hash given");
344 }
345
346 for (i = 0; i <= T_MASK; i++) {
347 counts[i] = 0;
348 }
349
350 rb_objspace_each_objects(cos_i, &counts[0]);
351
352 if (hash == Qnil) {
353 hash = rb_hash_new();
354 }
355 else if (!RHASH_EMPTY_P(hash)) {
356 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
357 }
358
359 for (i = 0; i <= T_MASK; i++) {
360 if (counts[i]) {
361 VALUE type = type2sym(i);
362 total += counts[i];
363 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
364 }
365 }
366 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
367 return hash;
368 }
369
370 static int
371 cn_i(void *vstart, void *vend, size_t stride, void *n)
372 {
373 size_t *nodes = (size_t *)n;
374 VALUE v = (VALUE)vstart;
375
376 for (; v != (VALUE)vend; v += stride) {
377 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
378 size_t s = nd_type((NODE *)v);
379 nodes[s]++;
380 }
381 }
382
383 return 0;
384 }
385
386 /*
387 * call-seq:
388 * ObjectSpace.count_nodes([result_hash]) -> hash
389 *
390 * Counts nodes for each node type.
391 *
392 * This method is not for ordinary Ruby programmers, but for MRI developers
393 * who have interest in MRI performance and memory usage.
394 *
395 * It returns a hash as:
396 * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
397 *
398 * If the optional argument, result_hash, is given,
399 * it is overwritten and returned.
400 * This is intended to avoid probe effect.
401 *
402 * The contents of the returned hash is implementation defined.
403 * It may be changed in future.
404 *
405 * This method is not expected to work except C Ruby.
406 */
407
408 static VALUE
409 count_nodes(int argc, VALUE *argv, VALUE os)
410 {
411 size_t nodes[NODE_LAST+1];
412 size_t i;
413 VALUE hash;
414
415 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
416 if (!RB_TYPE_P(hash, T_HASH))
417 rb_raise(rb_eTypeError, "non-hash given");
418 }
419
420 for (i = 0; i <= NODE_LAST; i++) {
421 nodes[i] = 0;
422 }
423
424 rb_objspace_each_objects(cn_i, &nodes[0]);
425
426 if (hash == Qnil) {
427 hash = rb_hash_new();
428 }
429 else if (!RHASH_EMPTY_P(hash)) {
430 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
431 }
432
433 for (i=0; i<NODE_LAST; i++) {
434 if (nodes[i] != 0) {
435 VALUE node;
436 switch (i) {
437 #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
438 COUNT_NODE(NODE_SCOPE);
439 COUNT_NODE(NODE_BLOCK);
440 COUNT_NODE(NODE_IF);
441 COUNT_NODE(NODE_CASE);
442 COUNT_NODE(NODE_WHEN);
443 COUNT_NODE(NODE_OPT_N);
444 COUNT_NODE(NODE_WHILE);
445 COUNT_NODE(NODE_UNTIL);
446 COUNT_NODE(NODE_ITER);
447 COUNT_NODE(NODE_FOR);
448 COUNT_NODE(NODE_BREAK);
449 COUNT_NODE(NODE_NEXT);
450 COUNT_NODE(NODE_REDO);
451 COUNT_NODE(NODE_RETRY);
452 COUNT_NODE(NODE_BEGIN);
453 COUNT_NODE(NODE_RESCUE);
454 COUNT_NODE(NODE_RESBODY);
455 COUNT_NODE(NODE_ENSURE);
456 COUNT_NODE(NODE_AND);
457 COUNT_NODE(NODE_OR);
458 COUNT_NODE(NODE_MASGN);
459 COUNT_NODE(NODE_LASGN);
460 COUNT_NODE(NODE_DASGN);
461 COUNT_NODE(NODE_DASGN_CURR);
462 COUNT_NODE(NODE_GASGN);
463 COUNT_NODE(NODE_IASGN);
464 COUNT_NODE(NODE_IASGN2);
465 COUNT_NODE(NODE_CDECL);
466 COUNT_NODE(NODE_CVASGN);
467 COUNT_NODE(NODE_CVDECL);
468 COUNT_NODE(NODE_OP_ASGN1);
469 COUNT_NODE(NODE_OP_ASGN2);
470 COUNT_NODE(NODE_OP_ASGN_AND);
471 COUNT_NODE(NODE_OP_ASGN_OR);
472 COUNT_NODE(NODE_OP_CDECL);
473 COUNT_NODE(NODE_CALL);
474 COUNT_NODE(NODE_FCALL);
475 COUNT_NODE(NODE_VCALL);
476 COUNT_NODE(NODE_SUPER);
477 COUNT_NODE(NODE_ZSUPER);
478 COUNT_NODE(NODE_ARRAY);
479 COUNT_NODE(NODE_ZARRAY);
480 COUNT_NODE(NODE_VALUES);
481 COUNT_NODE(NODE_HASH);
482 COUNT_NODE(NODE_RETURN);
483 COUNT_NODE(NODE_YIELD);
484 COUNT_NODE(NODE_LVAR);
485 COUNT_NODE(NODE_DVAR);
486 COUNT_NODE(NODE_GVAR);
487 COUNT_NODE(NODE_IVAR);
488 COUNT_NODE(NODE_CONST);
489 COUNT_NODE(NODE_CVAR);
490 COUNT_NODE(NODE_NTH_REF);
491 COUNT_NODE(NODE_BACK_REF);
492 COUNT_NODE(NODE_MATCH);
493 COUNT_NODE(NODE_MATCH2);
494 COUNT_NODE(NODE_MATCH3);
495 COUNT_NODE(NODE_LIT);
496 COUNT_NODE(NODE_STR);
497 COUNT_NODE(NODE_DSTR);
498 COUNT_NODE(NODE_XSTR);
499 COUNT_NODE(NODE_DXSTR);
500 COUNT_NODE(NODE_EVSTR);
501 COUNT_NODE(NODE_DREGX);
502 COUNT_NODE(NODE_DREGX_ONCE);
503 COUNT_NODE(NODE_ARGS);
504 COUNT_NODE(NODE_ARGS_AUX);
505 COUNT_NODE(NODE_OPT_ARG);
506 COUNT_NODE(NODE_KW_ARG);
507 COUNT_NODE(NODE_POSTARG);
508 COUNT_NODE(NODE_ARGSCAT);
509 COUNT_NODE(NODE_ARGSPUSH);
510 COUNT_NODE(NODE_SPLAT);
511 COUNT_NODE(NODE_TO_ARY);
512 COUNT_NODE(NODE_BLOCK_ARG);
513 COUNT_NODE(NODE_BLOCK_PASS);
514 COUNT_NODE(NODE_DEFN);
515 COUNT_NODE(NODE_DEFS);
516 COUNT_NODE(NODE_ALIAS);
517 COUNT_NODE(NODE_VALIAS);
518 COUNT_NODE(NODE_UNDEF);
519 COUNT_NODE(NODE_CLASS);
520 COUNT_NODE(NODE_MODULE);
521 COUNT_NODE(NODE_SCLASS);
522 COUNT_NODE(NODE_COLON2);
523 COUNT_NODE(NODE_COLON3);
524 COUNT_NODE(NODE_CREF);
525 COUNT_NODE(NODE_DOT2);
526 COUNT_NODE(NODE_DOT3);
527 COUNT_NODE(NODE_FLIP2);
528 COUNT_NODE(NODE_FLIP3);
529 COUNT_NODE(NODE_SELF);
530 COUNT_NODE(NODE_NIL);
531 COUNT_NODE(NODE_TRUE);
532 COUNT_NODE(NODE_FALSE);
533 COUNT_NODE(NODE_ERRINFO);
534 COUNT_NODE(NODE_DEFINED);
535 COUNT_NODE(NODE_POSTEXE);
536 COUNT_NODE(NODE_ALLOCA);
537 COUNT_NODE(NODE_BMETHOD);
538 COUNT_NODE(NODE_MEMO);
539 COUNT_NODE(NODE_IFUNC);
540 COUNT_NODE(NODE_DSYM);
541 COUNT_NODE(NODE_ATTRASGN);
542 COUNT_NODE(NODE_PRELUDE);
543 COUNT_NODE(NODE_LAMBDA);
544 #undef COUNT_NODE
545 default: node = INT2FIX(i);
546 }
547 rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
548 }
549 }
550 return hash;
551 }
552
553 static int
554 cto_i(void *vstart, void *vend, size_t stride, void *data)
555 {
556 VALUE hash = (VALUE)data;
557 VALUE v = (VALUE)vstart;
558
559 for (; v != (VALUE)vend; v += stride) {
560 if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
561 VALUE counter;
562 VALUE key = RBASIC(v)->klass;
563
564 if (key == 0) {
565 const char *name = rb_objspace_data_type_name(v);
566 if (name == 0) name = "unknown";
567 key = ID2SYM(rb_intern(name));
568 }
569
570 counter = rb_hash_aref(hash, key);
571 if (NIL_P(counter)) {
572 counter = INT2FIX(1);
573 }
574 else {
575 counter = INT2FIX(FIX2INT(counter) + 1);
576 }
577
578 rb_hash_aset(hash, key, counter);
579 }
580 }
581
582 return 0;
583 }
584
585 /*
586 * call-seq:
587 * ObjectSpace.count_tdata_objects([result_hash]) -> hash
588 *
589 * Counts objects for each T_DATA type.
590 *
591 * This method is not for ordinary Ruby programmers, but for MRI developers
592 * who interest on MRI performance.
593 *
594 * It returns a hash as:
595 * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
596 * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
597 * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
598 * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
599 * # T_DATA objects existing at startup on r32276.
600 *
601 * If the optional argument, result_hash, is given,
602 * it is overwritten and returned.
603 * This is intended to avoid probe effect.
604 *
605 * The contents of the returned hash is implementation defined.
606 * It may be changed in future.
607 *
608 * In this version, keys are Class object or Symbol object.
609 * If object is kind of normal (accessible) object, the key is Class object.
610 * If object is not a kind of normal (internal) object, the key is symbol
611 * name, registered by rb_data_type_struct.
612 *
613 * This method is not expected to work except C Ruby.
614 *
615 */
616
617 static VALUE
618 count_tdata_objects(int argc, VALUE *argv, VALUE self)
619 {
620 VALUE hash;
621
622 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
623 if (!RB_TYPE_P(hash, T_HASH))
624 rb_raise(rb_eTypeError, "non-hash given");
625 }
626
627 if (hash == Qnil) {
628 hash = rb_hash_new();
629 }
630 else if (!RHASH_EMPTY_P(hash)) {
631 st_foreach(RHASH_TBL(hash), set_zero_i, hash);
632 }
633
634 rb_objspace_each_objects(cto_i, (void *)hash);
635
636 return hash;
637 }
638
639 static void
640 iow_mark(void *ptr)
641 {
642 rb_gc_mark((VALUE)ptr);
643 }
644
645 static size_t
646 iow_size(const void *ptr)
647 {
648 VALUE obj = (VALUE)ptr;
649 return memsize_of(obj);
650 }
651
652 static const rb_data_type_t iow_data_type = {
653 "ObjectSpace::InternalObjectWrapper",
654 {iow_mark, 0, iow_size,},
655 };
656
657 static VALUE rb_mInternalObjectWrapper;
658
659 static VALUE
660 iow_newobj(VALUE obj)
661 {
662 return rb_data_typed_object_alloc(rb_mInternalObjectWrapper, (void *)obj, &iow_data_type);
663 }
664
665 static VALUE
666 iow_type(VALUE self)
667 {
668 VALUE obj = (VALUE)DATA_PTR(self);
669 return type2sym(BUILTIN_TYPE(obj));
670 }
671
672 static VALUE
673 iow_inspect(VALUE self)
674 {
675 VALUE obj = (VALUE)DATA_PTR(self);
676 VALUE type = type2sym(BUILTIN_TYPE(obj));
677
678 return rb_sprintf("#<InternalObject:%p %s>", (void *)obj, rb_id2name(SYM2ID(type)));
679 }
680
681 static VALUE
682 iow_internal_object_id(VALUE self)
683 {
684 VALUE obj = (VALUE)DATA_PTR(self);
685 return rb_obj_id(obj);
686 }
687
688 struct rof_data {
689 st_table *refs;
690 VALUE internals;
691 };
692
693 static void
694 reachable_object_from_i(VALUE obj, void *data_ptr)
695 {
696 struct rof_data *data = (struct rof_data *)data_ptr;
697 VALUE key = obj;
698 VALUE val = obj;
699
700 if (rb_objspace_markable_object_p(obj)) {
701 if (rb_objspace_internal_object_p(obj)) {
702 val = iow_newobj(obj);
703 rb_ary_push(data->internals, val);
704 }
705 st_insert(data->refs, key, val);
706 }
707 }
708
709 static int
710 collect_values(st_data_t key, st_data_t value, st_data_t data)
711 {
712 VALUE ary = (VALUE)data;
713 rb_ary_push(ary, (VALUE)value);
714 return ST_CONTINUE;
715 }
716
717 /*
718 * call-seq:
719 * ObjectSpace.reachable_objects_from(obj) -> array or nil
720 *
721 * [MRI specific feature] Return all reachable objects from `obj'.
722 *
723 * This method returns all reachable objects from `obj'.
724 * If `obj' has references two or more references to same object `x',
725 * them returned array only include one `x' object.
726 * If `obj' is non-markable (non-heap management) object such as
727 * true, false, nil, symbols and Fixnums (and Flonum) them it simply
728 * returns nil.
729 *
730 * If `obj' has references to internal object, then it returns
731 * instances of `ObjectSpace::InternalObjectWrapper' class.
732 * This object contains a reference to an internal object and
733 * you can check the type of internal object with `type' method.
734 *
735 * If `obj' is instance of `ObjectSpace::InternalObjectWrapper'
736 * class, then this method returns all reachable object from
737 * an internal object, which is pointed by `obj'.
738 *
739 * With this method, you can find memory leaks.
740 *
741 * This method is not expected to work except C Ruby.
742 *
743 * Example:
744 * ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
745 * #=> [Array, 'a', 'b', 'c']
746 *
747 * ObjectSpace.reachable_objects_from(['a', 'a', 'a'])
748 * #=> [Array, 'a', 'a', 'a'] # all 'a' strings have different object id
749 *
750 * ObjectSpace.reachable_objects_from([v = 'a', v, v])
751 * #=> [Array, 'a']
752 *
753 * ObjectSpace.reachable_objects_from(1)
754 * #=> nil # 1 is not markable (heap managed) object
755 *
756 */
757
758 static VALUE
759 reachable_objects_from(VALUE self, VALUE obj)
760 {
761 if (rb_objspace_markable_object_p(obj)) {
762 VALUE ret = rb_ary_new();
763 struct rof_data data;
764
765 if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
766 obj = (VALUE)DATA_PTR(obj);
767 }
768
769 data.refs = st_init_numtable();
770 data.internals = rb_ary_new();
771
772 rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
773
774 st_foreach(data.refs, collect_values, (st_data_t)ret);
775 return ret;
776 }
777 else {
778 return Qnil;
779 }
780 }
781
782 /* objspace library extends ObjectSpace module and add several
783 * methods to get internal statistic information about
784 * object/memory management.
785 *
786 * Generally, you *SHOULD NOT*use this library if you do not know
787 * about the MRI implementation. Mainly, this library is for (memory)
788 * profiler developers and MRI developers who need to know how MRI
789 * memory usage.
790 */
791
792 void
793 Init_objspace(void)
794 {
795 VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
796
797 rb_define_module_function(rb_mObjSpace, "memsize_of", memsize_of_m, 1);
798 rb_define_module_function(rb_mObjSpace, "memsize_of_all", memsize_of_all_m, -1);
799
800 rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
801 rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
802 rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
803
804 rb_define_module_function(rb_mObjSpace, "reachable_objects_from", reachable_objects_from, 1);
805
806 rb_mInternalObjectWrapper = rb_define_class_under(rb_mObjSpace, "InternalObjectWrapper", rb_cObject);
807 rb_define_method(rb_mInternalObjectWrapper, "type", iow_type, 0);
808 rb_define_method(rb_mInternalObjectWrapper, "inspect", iow_inspect, 0);
809 rb_define_method(rb_mInternalObjectWrapper, "internal_object_id", iow_internal_object_id, 0);
810 }
data
VALUE data
Definition: tcltklib.c:3368
RB_TYPE_P
#define RB_TYPE_P(obj, type)
nd_type
#define nd_type(n)
NODE_DREGX_ONCE
#define NODE_DREGX_ONCE
NODE_IF
#define NODE_IF
NODE_RESCUE
#define NODE_RESCUE
count_objects_size
static VALUE count_objects_size(int argc, VALUE *argv, VALUE os)
Definition: objspace.c:334
NODE_RETRY
#define NODE_RETRY
NODE_DEFN
#define NODE_DEFN
ROBJECT_EMBED
#define ROBJECT_EMBED
n
ssize_t n
Definition: bigdecimal.c:5655
iow_data_type
static const rb_data_type_t iow_data_type
Definition: objspace.c:652
ary
volatile VALUE ary
Definition: tcltklib.c:9713
NODE_FALSE
#define NODE_FALSE
NODE_OR
#define NODE_OR
NODE_LAMBDA
#define NODE_LAMBDA
RSTRUCT_LEN
#define RSTRUCT_LEN(st)
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:290
T_STRUCT
#define T_STRUCT
rb_mInternalObjectWrapper
static VALUE rb_mInternalObjectWrapper
Definition: objspace.c:657
T_MATCH
#define T_MATCH
st_table
Definition: ripper.y:77
NODE_DSYM
#define NODE_DSYM
FL_TEST
#define FL_TEST(x, f)
NODE_DEFS
#define NODE_DEFS
node.h
Init_objspace
void Init_objspace(void)
Definition: objspace.c:793
NODE_HASH
#define NODE_HASH
NODE_DOT3
#define NODE_DOT3
ruby.h
FL_EXIVAR
#define FL_EXIVAR
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:272
T_ICLASS
#define T_ICLASS
SIZET2NUM
#define SIZET2NUM(v)
NODE_VCALL
#define NODE_VCALL
rb_const_get
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1876
onig_memsize
size_t onig_memsize(const regex_t *reg)
Definition: regcomp.c:5592
NODE_NTH_REF
#define NODE_NTH_REF
i
ssize_t i
Definition: bigdecimal.c:5655
NODE_TRUE
#define NODE_TRUE
rb_io_t
Definition: io.h:63
T_NODE
#define T_NODE
RSTRUCT_EMBED_LEN_MASK
#define RSTRUCT_EMBED_LEN_MASK
NODE_ITER
#define NODE_ITER
NODE_ARGS
#define NODE_ARGS
NODE_MATCH3
#define NODE_MATCH3
ret
int ret
Definition: tcltklib.c:280
NODE_UNDEF
#define NODE_UNDEF
RHASH
#define RHASH(obj)
NODE_ENSURE
#define NODE_ENSURE
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:511
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
ROBJECT
#define ROBJECT(obj)
NODE_PRELUDE
#define NODE_PRELUDE
RHASH_TBL
#define RHASH_TBL(h)
NIL_P
NIL_P(eventloop_thread)
Definition: tcltklib.c:4068
RFILE
#define RFILE(obj)
T_ARRAY
#define T_ARRAY
NODE_SUPER
#define NODE_SUPER
NODE_EVSTR
#define NODE_EVSTR
cto_i
static int cto_i(void *vstart, void *vend, size_t stride, void *data)
Definition: objspace.c:554
NODE_RESBODY
#define NODE_RESBODY
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:545
RSTRUCT
#define RSTRUCT(obj)
NODE_DXSTR
#define NODE_DXSTR
NODE_CASE
#define NODE_CASE
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
T_HASH
#define T_HASH
rmatch::regs
struct re_registers regs
Definition: re.h:39
memsize_of_all_m
static VALUE memsize_of_all_m(int argc, VALUE *argv, VALUE self)
Definition: objspace.c:238
rb_obj_id
VALUE rb_obj_id(VALUE)
Definition: gc.c:1688
gc.h
T_FILE
#define T_FILE
st_memsize
size_t st_memsize(const st_table *)
Definition: st.c:342
reachable_object_from_i
static void reachable_object_from_i(VALUE obj, void *data_ptr)
Definition: objspace.c:694
NODE_STR
#define NODE_STR
T_NIL
#define T_NIL
rb_objspace_each_objects
void rb_objspace_each_objects(each_obj_callback *callback, void *data)
Definition: gc.c:1128
NODE_REDO
#define NODE_REDO
NODE_NEXT
#define NODE_NEXT
rb_objspace_markable_object_p
int rb_objspace_markable_object_p(VALUE obj)
Definition: gc.c:2576
NODE_XSTR
#define NODE_XSTR
NODE_BLOCK_PASS
#define NODE_BLOCK_PASS
ruby_value_type
ruby_value_type
Definition: ripper.y:450
rmatch::char_offset_num_allocated
int char_offset_num_allocated
Definition: re.h:42
NODE_MATCH2
#define NODE_MATCH2
ID2SYM
#define ID2SYM(x)
NODE_FOR
#define NODE_FOR
T_FLOAT
#define T_FLOAT
T_OBJECT
#define T_OBJECT
io.h
NODE_UNTIL
#define NODE_UNTIL
NODE_ARGS_AUX
#define NODE_ARGS_AUX
NODE_GASGN
#define NODE_GASGN
rof_data::internals
VALUE internals
Definition: objspace.c:690
rb_objspace_data_type_name
const char * rb_objspace_data_type_name(VALUE obj)
Definition: gc.c:749
NODE_POSTEXE
#define NODE_POSTEXE
NODE_OP_CDECL
#define NODE_OP_CDECL
RNode
Definition: ripper.y:240
total_data::klass
VALUE klass
Definition: objspace.c:179
RBIGNUM_LEN
#define RBIGNUM_LEN(b)
T_COMPLEX
#define T_COMPLEX
st_data_t
unsigned long st_data_t
Definition: ripper.y:35
NODE_CLASS
#define NODE_CLASS
NODE_IFUNC
#define NODE_IFUNC
NODE_WHILE
#define NODE_WHILE
hash
VALUE hash
Definition: tkutil.c:267
iow_type
static VALUE iow_type(VALUE self)
Definition: objspace.c:666
iow_size
static size_t iow_size(const void *ptr)
Definition: objspace.c:646
NODE_LVAR
#define NODE_LVAR
CASE_TYPE
#define CASE_TYPE(t)
NODE_LASGN
#define NODE_LASGN
NODE_OP_ASGN_AND
#define NODE_OP_ASGN_AND
NODE_WHEN
#define NODE_WHEN
Qnil
#define Qnil
Definition: tcltklib.c:1896
val
#define val
Definition: tcltklib.c:1949
RCLASS_IV_TBL
#define RCLASS_IV_TBL(c)
NODE_YIELD
#define NODE_YIELD
NODE_FLIP2
#define NODE_FLIP2
NODE_BLOCK
#define NODE_BLOCK
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:473
NODE_DASGN_CURR
#define NODE_DASGN_CURR
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:424
NODE_AND
#define NODE_AND
flags
int flags
Definition: tcltklib.c:3023
T_RATIONAL
#define T_RATIONAL
rb_gc_mark
void rb_gc_mark(VALUE)
Definition: gc.c:2598
reachable_objects_from
static VALUE reachable_objects_from(VALUE self, VALUE obj)
Definition: objspace.c:759
obj
static VALUE VALUE obj
Definition: tcltklib.c:3158
FIX2INT
#define FIX2INT(x)
INT2FIX
#define INT2FIX(i)
T_STRING
#define T_STRING
NODE_ARGSCAT
#define NODE_ARGSCAT
NODE_COLON2
#define NODE_COLON2
onig_region_memsize
size_t onig_region_memsize(const OnigRegion *regs)
Definition: regcomp.c:5607
NODE_ZSUPER
#define NODE_ZSUPER
NODE_BMETHOD
#define NODE_BMETHOD
NODE_MODULE
#define NODE_MODULE
memsize_of
static size_t memsize_of(VALUE obj)
Definition: objspace.c:42
key
static int VALUE key
Definition: tkutil.c:265
rof_data::refs
st_table * refs
Definition: objspace.c:689
total_i
static int total_i(void *vstart, void *vend, size_t stride, void *ptr)
Definition: objspace.c:183
RBIGNUM_DIGITS
#define RBIGNUM_DIGITS(b)
memsize_of_m
static VALUE memsize_of_m(VALUE self, VALUE obj)
Definition: objspace.c:172
count_nodes
static VALUE count_nodes(int argc, VALUE *argv, VALUE os)
Definition: objspace.c:409
rb_classext_t
struct rb_classext_struct rb_classext_t
Definition: ripper.y:735
argv
VALUE * argv
Definition: tcltklib.c:1971
NODE_MEMO
#define NODE_MEMO
rb_hash_aset
VALUE rb_hash_aset(VALUE, VALUE, VALUE)
iow_inspect
static VALUE iow_inspect(VALUE self)
Definition: objspace.c:673
rb_define_module_function
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1512
st_foreach
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1000
iow_internal_object_id
static VALUE iow_internal_object_id(VALUE self)
Definition: objspace.c:682
NODE_NIL
#define NODE_NIL
NODE_ATTRASGN
#define NODE_ATTRASGN
rb_objspace_internal_object_p
int rb_objspace_internal_object_p(VALUE obj)
Definition: gc.c:1170
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1270
value
volatile VALUE value
Definition: tcltklib.c:9442
NODE_COLON3
#define NODE_COLON3
NODE_DEFINED
#define NODE_DEFINED
rb_io_memsize
size_t rb_io_memsize(const rb_io_t *)
Definition: io.c:4209
count_tdata_objects
static VALUE count_tdata_objects(int argc, VALUE *argv, VALUE self)
Definition: objspace.c:618
NODE_MASGN
#define NODE_MASGN
T_REGEXP
#define T_REGEXP
s
register char * s
Definition: os2.c:56
NODE_CONST
#define NODE_CONST
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
internal.h
NODE_VALIAS
#define NODE_VALIAS
NODE_GVAR
#define NODE_GVAR
NODE_CDECL
#define NODE_CDECL
NODE_LIT
#define NODE_LIT
type
int type
Definition: tcltklib.c:111
T_FIXNUM
#define T_FIXNUM
argc
int argc
Definition: tcltklib.c:1970
rof_data
Definition: objspace.c:688
set_zero_i
static int set_zero_i(st_data_t key, st_data_t val, st_data_t arg)
Definition: objspace.c:251
NODE_ERRINFO
#define NODE_ERRINFO
rb_ary_memsize
RUBY_FUNC_EXPORTED size_t rb_ary_memsize(VALUE ary)
Definition: array.c:479
ST_CONTINUE
Definition: ripper.y:108
BDIGIT
#define BDIGIT
Definition: ripper.y:184
NODE_ARGSPUSH
#define NODE_ARGSPUSH
NODE_BACK_REF
#define NODE_BACK_REF
NODE_MATCH
#define NODE_MATCH
re.h
total_data::total
size_t total
Definition: objspace.c:178
NODE_ALIAS
#define NODE_ALIAS
ptr
return ptr
Definition: tcltklib.c:784
NODE_CVDECL
#define NODE_CVDECL
rmatch
Definition: re.h:38
NODE_DASGN
#define NODE_DASGN
collect_values
static int collect_values(st_data_t key, st_data_t value, st_data_t data)
Definition: objspace.c:710
T_BIGNUM
#define T_BIGNUM
T_TRUE
#define T_TRUE
NODE_TO_ARY
#define NODE_TO_ARY
arg
arg
Definition: ripper.y:1315
T_SYMBOL
#define T_SYMBOL
size
int size
Definition: encoding.c:52
NODE_FCALL
#define NODE_FCALL
FL_SINGLETON
#define FL_SINGLETON
NODE_FLIP3
#define NODE_FLIP3
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:582
cos_i
static int cos_i(void *vstart, void *vend, size_t stride, void *data)
Definition: objspace.c:260
T_CLASS
#define T_CLASS
NODE_DVAR
#define NODE_DVAR
NODE_CREF
#define NODE_CREF
rb_objspace_reachable_objects_from
void rb_objspace_reachable_objects_from(VALUE obj, void(func)(VALUE, void *), void *data)
Definition: gc.c:3336
rb_data_type_struct
Definition: ripper.y:960
NODE_ZARRAY
#define NODE_ZARRAY
DATA_PTR
DATA_PTR(self)
NODE_CVAR
#define NODE_CVAR
NODE_BREAK
#define NODE_BREAK
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
RBASIC
#define RBASIC(obj)
NODE_LAST
#define NODE_LAST
NODE_OP_ASGN2
#define NODE_OP_ASGN2
NODE_DSTR
#define NODE_DSTR
iow_newobj
static VALUE iow_newobj(VALUE obj)
Definition: objspace.c:660
type2sym
static VALUE type2sym(enum ruby_value_type i)
Definition: objspace.c:274
NODE_ALLOCA
#define NODE_ALLOCA
NODE_SCLASS
#define NODE_SCLASS
NODE_BEGIN
#define NODE_BEGIN
NODE_POSTARG
#define NODE_POSTARG
st_insert
int st_insert(st_table *, st_data_t, st_data_t)
st.h
NODE_OP_ASGN1
#define NODE_OP_ASGN1
NODE_CVASGN
#define NODE_CVASGN
T_MODULE
#define T_MODULE
RCLASS_IV_INDEX_TBL
#define RCLASS_IV_INDEX_TBL(c)
cn_i
static int cn_i(void *vstart, void *vend, size_t stride, void *n)
Definition: objspace.c:371
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:234
T_UNDEF
#define T_UNDEF
rb_str_memsize
size_t rb_str_memsize(VALUE)
Definition: string.c:838
rb_id2name
const char * rb_id2name(ID id)
Definition: ripper.c:17005
NODE_CALL
#define NODE_CALL
BUILTIN_TYPE
#define BUILTIN_TYPE(x)
NODE_OPT_N
#define NODE_OPT_N
RMATCH
#define RMATCH(obj)
Definition: re.h:53
rb_hash_aref
VALUE rb_hash_aref(VALUE, VALUE)
Definition: hash.c:560
VALUE
unsigned long VALUE
Definition: ripper.y:104
NODE_IVAR
#define NODE_IVAR
regint.h
RREGEXP
#define RREGEXP(obj)
rb_data_typed_object_alloc
VALUE rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *)
Definition: gc.c:722
NODE_DOT2
#define NODE_DOT2
NODE_KW_ARG
#define NODE_KW_ARG
NODE_DREGX
#define NODE_DREGX
NODE_OP_ASGN_OR
#define NODE_OP_ASGN_OR
NODE_IASGN
#define NODE_IASGN
NODE_RETURN
#define NODE_RETURN
SPECIAL_CONST_P
#define SPECIAL_CONST_P(x)
RHASH_EMPTY_P
#define RHASH_EMPTY_P(h)
NODE_ARRAY
#define NODE_ARRAY
NODE_SPLAT
#define NODE_SPLAT
rb_intern
#define rb_intern(str)
v
BDIGIT v
Definition: bigdecimal.c:5656
RCLASS_M_TBL
#define RCLASS_M_TBL(c)
total_data
Definition: objspace.c:177
T_DATA
#define T_DATA
name
const char * name
Definition: nkf.c:208
rb_generic_ivar_memsize
size_t rb_generic_ivar_memsize(VALUE)
Definition: variable.c:1038
RNODE
#define RNODE(obj)
NODE_SCOPE
#define NODE_SCOPE
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
NODE_IASGN2
#define NODE_IASGN2
NODE_SELF
#define NODE_SELF
RBIGNUM_EMBED_FLAG
#define RBIGNUM_EMBED_FLAG
SYM2ID
#define SYM2ID(x)
NODE_BLOCK_ARG
#define NODE_BLOCK_ARG
rb_objspace_data_type_memsize
size_t rb_objspace_data_type_memsize(VALUE obj)
Definition: gc.c:738
T_NONE
#define T_NONE
T_MASK
#define T_MASK
Definition: md5.c:131
T_FALSE
#define T_FALSE
rmatch_offset
Definition: re.h:33
NODE_VALUES
#define NODE_VALUES
COUNT_NODE
#define COUNT_NODE(n)
iow_mark
static void iow_mark(void *ptr)
Definition: objspace.c:640
RCLASS
#define RCLASS(obj)
T_ZOMBIE
#define T_ZOMBIE
NODE_OPT_ARG
#define NODE_OPT_ARG