Project

General

Profile

Actions

Bug #16788

closed

T_CLASS counts classes double

Added by ana06 (Ana Maria Martinez Gomez) over 1 year ago. Updated over 1 year ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
1.9 to master
[ruby-core:97896]

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.

From https://stackoverflow.com/questions/61031735

Actions #1

Updated by ana06 (Ana Maria Martinez Gomez) over 1 year ago

  • ruby -v changed from 1.9 to master to 1.9.3 to master

Updated by jeremyevans0 (Jeremy Evans) over 1 year ago

  • ruby -v changed from 1.9.3 to master to 1.9 to master
  • Status changed from Open to Rejected

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 1 year 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 1 year 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 1 year 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).

Actions

Also available in: Atom PDF