6

This program

class ObjectGarden
    class << self.clone
            puts self.object_id
    end
end

puts ObjectGarden.clone.object_id

When run on Linux (have tested on RHEL) generates distinct object_ids across multiple runs as I had expected. However when I run it on Windows, I get same output across multiple runs. And no matter what I do (hibernate/shutdown/"infamous blue screen" and restart) object_ids won't change.

I also notice that object_id on Windows changes iff I change the content (even an insignificant change like add a new line or comment) of the program.

Why is this difference between Windows and Linux implementations? And since I don't have access to OS X can someone please run it on a Mac and document the result.

I'm using Ruby 1.9.2-p136 on Windows and Ruby 1.9.2-p180 on Linux.

saihgala
  • 5,724
  • 3
  • 34
  • 31
  • 1
    The `object_id` changes if you modify the object? That goes against what [Ruby's documentation](http://ruby-doc.org/core-1.9.3/Object.html#method-i-object_id) states: `The same number will be returned on all calls to id for a given object`. Very interesting. I'd just like to note that `object_id` apparently just converts the internal `VALUE` to a `Fixnum`. The former is probably just an integer that the Ruby VM uses to identify objects. – Matheus Moreira Nov 16 '12 at 14:37
  • 1
    Why do you care ? You shouldn't be relying on the precise value of object_id – Frederick Cheung Nov 16 '12 at 14:45
  • @Frederick I just found it interesting and want to know if there are different algorithms per platform to generate object_id's. And if yes why so? What purpose does it solve and/or what are the OS constraints that caused such design? – saihgala Nov 16 '12 at 14:53
  • 2
    I think it's (basically) the address in memory of the object (except for immediates like nil/true/false/fixnum/symbol. There doesn't appear to be a per OS code path, however different OSs will have different approaches to memory layout (in particular ASLR etc) – Frederick Cheung Nov 16 '12 at 14:57
  • @FrederickCheung the singleton class of a clone of ObjectGarden should always be a different instance than another distinct clone of ObjectGarden regardless of memory layout. – dbenhur Nov 16 '12 at 20:01
  • @Matheus Moreira He said the object_id changed if he added "a new line or comment", which suggests he didn't mean runtime change, but code change. So wasn't really modifying the *object*, as in *instance*. – Matt Dec 05 '12 at 13:39
  • When I ran your example on Ruby in Windows XP, I got reproducible object IDs. I tried it with 1.9.3p194 and 1.8.7p352; the results were not consistent between the two different versions, _but_ they _were_ still consistent among multiple runs on the same version. Then when I ran your example with Ruby 1.9.2p290 on Windows 7, I got different object IDs every time. So I suspect this is due to a cruder memory management scheme in Windows XP that was changed in later versions of the Windows kernel. – L2G Dec 06 '12 at 19:04
  • By the way, [the source code documents some of the secret(?) meaning hidden in object IDs](https://github.com/ruby/ruby/blob/dc098a569ef4ed60ad9d3e10a66e90b05600deb9/gc.c#L2835). – L2G Dec 06 '12 at 19:13
  • @L2G perhaps you're right about Windows XP and 7, because nothing else I have found so far that explains such behaviour. – saihgala Dec 07 '12 at 09:36
  • Tried this on OSX 10.6.8, ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin10.8.0] distinct ids are generated – mechanicalfish Dec 07 '12 at 16:28
  • @mechanicalfish thanks thats what I had expected but its good to finally have it confirmed – saihgala Dec 07 '12 at 17:45

1 Answers1

1

For most objects in ruby, the number you get from #object_id is actually the pointer to the internal C data structure for the object. This data structure in turn has space allocated for it by whatever memory allocator the ruby implementation/build uses.

Without reading code, I will guess that the linux version is producing different results every time because something, either ruby or the C allocator, is intentionally using a random offset for allocations or pointers, to make them hard to guess and thus make the program more secure.

There is only one guarantee that ruby will make about object_id's: as long as a particular object exists, its object_id will be unique to that ruby interpreter and will not change. That's all. You can even get the same object_id for an object as one that was created previously and later garbage collected, if it ends up getting the same chunk of memory.

Note also, if you do something like this:

irb(main):001:0> a = "hi"
=> "hi"
irb(main):002:0> a.object_id
=> 14348380
irb(main):003:0> a = a + " there"
=> "hi there"
irb(main):004:0> a.object_id
=> 14197020

The line a = a + " there" actually creates a new object, with a new object_id, where as using #concat doesn't:

irb(main):005:0> a = "hi"
=> "hi"
irb(main):006:0> a.object_id
=> 12031400
irb(main):007:0> a.concat " there"
=> "hi there"
irb(main):008:0> a.object_id
=> 12031400

Note also that in ruby, assignment binds the assigned variable to the object, so assigning one variable to another points them both at the same object:

irb(main):011:0> a = "hi"
=> "hi"
irb(main):012:0> a.object_id
=> 12081640
irb(main):013:0> b = a
=> "hi"
irb(main):014:0> b.object_id
=> 12081640

So changing one variable will change the other:

irb(main):015:0> a.concat " there"
=> "hi there"
irb(main):016:0> b
=> "hi there"
Michael Slade
  • 13,802
  • 2
  • 39
  • 44
  • Michael, but it does not explain why ruby on Windows behaves the way it does i.e. sort of extends the guarantee that object_id stays unique across multiple instances of the ruby interpreter. – saihgala Dec 11 '12 at 11:55