From: Tanaka Akira Date: 2007-09-30T13:31:52+09:00 Subject: Re: gc.c -- possible logic error? In article , Hugh Sasse writes: > I've been looking at Tom Copeland's memory allocation problem: > > http://tomcopeland.blogs.com/juniordeveloper/2007/09/tracking-down-a.html I think OpenStruct needs much more memory than Hash. It needs accessor methods for all member of all objects. I implemented ObjectSpace.count_objects to count objects. % ./ruby -rpp -e 'pp ObjectSpace.count_objects' {:T_ARRAY=>1261, :T_BIGNUM=>42, :T_CLASS=>418, :T_DATA=>297, :T_FILE=>5, :T_FLOAT=>6, :T_HASH=>3, :T_ICLASS=>21, :T_MATCH=>1, :T_MODULE=>18, :T_NODE=>10918, :T_OBJECT=>7, :T_REGEXP=>5, :T_STRING=>3101, :T_VALUES=>2, :freed=>11895} This means that there are 1261 arrays, etc. ObjectSpace.count_objects can be used to count objects required by Hash/OpenStruct. Hash: % ./ruby -e ' o = {} GC.start; c = ObjectSpace.count_objects 10.times {|i| o["foo#{i}"] = 1 GC.start; c2 = ObjectSpace.count_objects c.keys.each {|k| n = c2[k] - c[k]; print "#{k}:#{n} " if 0as.basic.flags) { + counts[BUILTIN_TYPE(p)]++; + } + else { + freed++; + } + } + } + + hash = rb_hash_new(); + rb_hash_aset(hash, ID2SYM(rb_intern("freed")), LONG2NUM(freed)); + for (i = 0; i <= T_MASK; i++) { + VALUE type; + switch (i) { + case T_NONE: type = ID2SYM(rb_intern("T_NONE")); break; + case T_NIL: type = ID2SYM(rb_intern("T_NIL")); break; + case T_OBJECT: type = ID2SYM(rb_intern("T_OBJECT")); break; + case T_CLASS: type = ID2SYM(rb_intern("T_CLASS")); break; + case T_ICLASS: type = ID2SYM(rb_intern("T_ICLASS")); break; + case T_MODULE: type = ID2SYM(rb_intern("T_MODULE")); break; + case T_FLOAT: type = ID2SYM(rb_intern("T_FLOAT")); break; + case T_STRING: type = ID2SYM(rb_intern("T_STRING")); break; + case T_REGEXP: type = ID2SYM(rb_intern("T_REGEXP")); break; + case T_ARRAY: type = ID2SYM(rb_intern("T_ARRAY")); break; + case T_FIXNUM: type = ID2SYM(rb_intern("T_FIXNUM")); break; + case T_HASH: type = ID2SYM(rb_intern("T_HASH")); break; + case T_STRUCT: type = ID2SYM(rb_intern("T_STRUCT")); break; + case T_BIGNUM: type = ID2SYM(rb_intern("T_BIGNUM")); break; + case T_FILE: type = ID2SYM(rb_intern("T_FILE")); break; + case T_TRUE: type = ID2SYM(rb_intern("T_TRUE")); break; + case T_FALSE: type = ID2SYM(rb_intern("T_FALSE")); break; + case T_DATA: type = ID2SYM(rb_intern("T_DATA")); break; + case T_MATCH: type = ID2SYM(rb_intern("T_MATCH")); break; + case T_SYMBOL: type = ID2SYM(rb_intern("T_SYMBOL")); break; + case T_VALUES: type = ID2SYM(rb_intern("T_VALUES")); break; + case T_BLOCK: type = ID2SYM(rb_intern("T_BLOCK")); break; + case T_UNDEF: type = ID2SYM(rb_intern("T_UNDEF")); break; + case T_NODE: type = ID2SYM(rb_intern("T_NODE")); break; + default: type = INT2NUM(i); break; + } + if (counts[i]) + rb_hash_aset(hash, type, LONG2NUM(counts[i])); + } + + return hash; +} + /* * The GC module provides an interface to Ruby's mark and * sweep garbage collection mechanism. Some of the underlying methods @@ -2190,4 +2254,6 @@ rb_define_method(rb_mKernel, "hash", rb_obj_id, 0); rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0); rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0); + + rb_define_module_function(rb_mObSpace, "count_objects", count_objects, 0); } -- Tanaka Akira