For most objects in ruby, the number you get from #object_id is actually a pointer to the internal C data structure for the object. This data structure, in turn, has the space allocated to it by any memory allocator used in ruby implementation / construction.
Without reading the code, I will assume that the linux version produces different results every time, because something, whether it is a ruby or a C-allocator, intentionally uses a random offset for distributions or pointers to make them hard to guess and thus make the program more secure.
There is only one guarantee that ruby will do about object_id : as long as a specific object exists, its object_id will be unique to this ruby interpreter and will not change. All this. You can even get the same object_id for an object that was created earlier, and later garbage collected if it eventually gets the same piece of memory.
Note that 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
Line a = a + " there" actually creates a new object with a new object_id , where when using #concat fails:
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 associates an assigned variable with an object, so assigning one variable to another points to them as one 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
Thus, changing one variable will change another:
irb(main):015:0> a.concat " there" => "hi there" irb(main):016:0> b => "hi there"