Bug #16788
closedT_CLASS counts classes double
Description
Consider the following code:
h = {}
ObjectSpace.count_objects(h)
puts "Counts: #{ h[:T_CLASS] }, #{ h[:T_ICLASS] }"
objects = []
classes = []
ObjectSpace.each_object(Object){|x| objects << x}
ObjectSpace.each_object(Class){|x| classes << x}
class Test
end
objects2 = []
classes2 = []
ObjectSpace.each_object(Object){|x| objects2 << x}
ObjectSpace.each_object(Class){|x| classes2 << x}
objects_ids = objects.map(&:object_id)
new_objects = objects2.reject { |e| objects_ids.include? e.object_id }
puts "New objects belongs to the classes: #{ new_objects.map(&:class).uniq }"
puts "New classes: #{classes2 - classes}"
h = {}
ObjectSpace.count_objects(h)
puts "Counts: #{ h[:T_CLASS] }, #{ h[:T_ICLASS] }"
The result is the following:
Counts: 690, 46
New objects belongs to the classes: [Array, Class]
New classes: [Test]
Counts: 692, 46
This means that the number of T_CLASS
is increased by 2 with the creation of 1 class. Why is this the case? Is this a bug?
Consider the slightly modified code with:
class Test
def self.foo
end
end
In this case the Singleton class is also created and the results are:
Counts: 690, 46
New objects belongs to the classes: [Array, Class]
New classes: [#<Class:Test>, Test]
Counts: 693, 46
In this case, T_CLASS
is increased by 3. So it seems like the issue is only with normal classes and not singleton ones.
Updated by ana06 (Ana Maria Martinez Gomez) over 4 years ago
- ruby -v changed from 1.9 to master to 1.9.3 to master
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- Status changed from Open to Rejected
- ruby -v changed from 1.9.3 to master to 1.9 to master
This is expected and not a bug. Creating a class automatically creates a singleton class. Output from debugger when doing c = Class.new
:
#0 class_alloc (flags=0, klass=120258865952) at class.c:172
#1 0x0000073abf1eadcd in rb_class_boot (super=0) at class.c:211
#2 0x0000073abf38971f in rb_class_s_alloc (klass=7951766573360) at object.c:1976
#3 0x0000073abf38a6cf in class_call_alloc_func (allocator=0x73abf389700 <rb_class_s_alloc>, klass=7951766573360) at object.c:2158
#4 0x0000073abf381383 in rb_class_alloc (klass=7951766573360) at object.c:2130
#5 0x0000073abf389549 in rb_class_s_new (argc=0, argv=0x73b07f5f040, klass=7951766573360) at object.c:2210
#0 class_alloc (flags=52, klass=11142131147240033036) at class.c:172
#1 0x0000073abf1eadcd in rb_class_boot (super=52) at class.c:211
#2 0x0000073abf1ecb73 in make_metaclass (klass=7949829093040) at class.c:502
#3 0x0000073abf1ecb18 in rb_make_metaclass (obj=7949829093040, unused=7950433580800) at class.c:591
#4 0x0000073abf3896b8 in rb_class_initialize (argc=0, argv=0x73b07f5f040, klass=7949829093040) at object.c:2075
Referencing the singleton class of a class automatically creates a singleton class of that singleton class. Output from debugger when doing c.singleton_class
:
#0 class_alloc (flags=52, klass=8589934593) at class.c:172
#1 0x0000073abf1eadcd in rb_class_boot (super=52) at class.c:211
#2 0x0000073abf1ecb73 in make_metaclass (klass=7949829093000) at class.c:502
#3 0x0000073abf1f0024 in rb_singleton_class (obj=7949829093040) at class.c:1803
#4 0x0000073abf38660f in rb_obj_singleton_class (obj=7949829093040) at object.c:325
This explains why you get 2 new classes for every class, and 3 if you reference the singleton class.
Updated by ana06 (Ana Maria Martinez Gomez) over 4 years ago
@jeremyevans0 (Jeremy Evans) thank you so much for your answer. Why are two singleton classes created and why only the second one is accesible to the user?
Also, could you please tell me how do you do to see the debugger output?
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
Unfortunately, I do not know the reason behind the automatic creation of singleton classes for classes. I'm guessing it is necessary for correct method lookup, but I'm not sure.
Looking at the repository, automatic creation of singleton classes for new classes has been there since one of the earliest commits (1998). Automatically creating the singleton class of the singleton class when referencing the singleton class of a class is newer, that is in 3a5c0bbcb5615b063d32aeee35b4f0f4227fb693.
In terms of the debugger, I created a file (e.g. t.rb
), containing:
ENV["TRACE"] = "1"
c = Class.new
c.singleton_class
Then I ran gdb ruby
, then inside gdb:
break class_alloc if getenv("TRACE")
set args t.rb
r
bt
c
bt
c
bt
c
Updated by Eregon (Benoit Daloze) over 4 years ago
The reason is documented here:
https://github.com/ruby/ruby/blob/f2c3848a5bf2bec0b27a6035c4b7399594c32509/class.c#L1775-L1778
Otherwise, methods on the class (i.e. class methods/singleton methods of that class) wouldn't inherit from the superclass's metaclass, which is necessary as the superclass's class methods should be available as the subclass's class methods (IIRC).
Updated by ana06 (Ana Maria Martinez Gomez) over 4 years ago
Thank you so much for the explanations @jeremyevans0 (Jeremy Evans) @Eregon (Benoit Daloze)!!!!