Search code examples
rubyirbobject-identity

Why does Ruby tend to assign object IDs in descending order?


I've noticed that objects have their IDs assigned in a counterintuitive fashion. The earlier an object is created, the greater its object ID. I would have thought they would have been assigned in ascending order, rather than the other way around.

For example:

obj1 = Object.new
obj2 = Object.new
obj3 = Object.new

p obj1.object_id # => 4806560
p obj2.object_id # => 4806540
p obj3.object_id # => 4806520

Why are they assigned in such a way and also why is there a step of 20, rather than 1 in code run by the Ruby interpreter, but a vastly greater difference between object IDs for code run by Ruby's irb?


Solution

  • Handwaving over many details, ruby allocates a chunk of the heap to put objects in:

    1 | 2 | 3 | 4 | 5
    

    Then traverses them in-order and adds them to a linked-list of free objects. This causes them to be in reverse order on the linked-list:

    freelist → NULL
    freelist → 1 → NULL
    freelist → 2 → 1 → NULL
    freelist → 3 → 2 → 1 → NULL
    freelist → 4 → 3 → 2 → 1 → NULL
    freelist → 5 → 4 → 3 → 2 → 1 → NULL
    

    When allocating an object ruby uses the first item on the linked list:

    object = freelist
    freelist = object.next_free
    

    So the freelist now looks like:

    freelist → 4 → 3 → 2 → 1 → NULL
    

    and further allocated objects will appear in reverse order across small allocations.

    When ruby needs to allocate a new chunk of heap to store more objects you'll see the object_id jump up then run down again.