Why does `ObjectSpace.each_object(String)` include just about any string?

202 views Asked by At

After comments by Mike H-R and Stefan to a question of mine, I noticed that ObjectSpace.each_object(String) includes just about any string I can think of:

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

or

strings = ObjectSpace.each_object(String).to_a
strings.include?("some random string") # => true

I thought that strings should include only strings that existed at that point. Why does it include just about any string?

Yet, when I count the length of strings, it returns a finite number:

ObjectSpace.each_object(String).to_a.length # => 15780

This is observed on Ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux] interpreter and irb.

Does this have anything to do with frozen string literal optimization introduced in Ruby 2.1?

2

There are 2 answers

7
Uri Agassi On BEST ANSWER

When writing code in the IRB strings are added to the ObjectSpace as they are typed:

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string") # => false

When trying to do it inside an rb file, the text is already there, because it is added when the file is parsed.

test.rb

strings = ObjectSpace.each_object(String)
strings.include?("some random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string") # => true

strings = ObjectSpace.each_object(String).to_a
strings.include?("some other random string " + "dynamically built") # => false
1
Ajedi32 On

That's because in order to pass "some random string" to the include? method on ObjectSpace's each_object iterator, you have to create the string "some random string" first.

Simply by asking ObjectSpace about the existence of "some random string", you are creating "some random string", so of course it exists in the object space. See what I'm saying? So that explains your first example.

In your second example when you get the array of string objects before referencing "some random string", you would think that you'd get false. As you noted though, that's not the case. I assume this is because you are using a string literal, and Ruby is optimizing your code by creating the string before you actually reference it. I don't know enough about Ruby's internals though to go into specifics on that.