Как работает назначение object_id?
Я играю с Ruby .object_id
и заметил, что в нескольких последовательных сеансах irb я получаю эти одинаковые результаты:
false.object_id // 0
true.object_id // 2
nil.object_id // 4
100.object_id // 201
Фактически, каждый целочисленный object_id представляется ((значение * 2) + 1).
С другой стороны, данная строка object_id никогда не будет прежней после выхода и повторного запуска irb.
Это вызывает несколько вопросов для меня:
- Существует ли известная схема, в которой определены определенные
object_id
? Другие в основном случайны?
- Иды для true, false и nil не являются последовательными. Есть ли способ спросить, какой объект представлен данным идентификатором? (Мне любопытно, к чему привязаны другие одиночные цифры и идентификаторы.)
- Не могли бы вы (не то, чтобы вы должны) писать обфускацию Ruby, где вы используете известные идентификаторы объектов, чтобы ссылаться на объекты, не называя их, например, "объект id 201 + object of id 19" означает "100 + 9"?
Update
Используя предложение Andrew Grimm, я попытался открыть другие объекты с низким идентификатором, но обнаружил, что:
- В этой последовательности больше нет четных объектов - идентификаторы 6, 8, 10 и т.д. не указывают ни на что.
- Как явствует из моего предыдущего эксперимента, все нечетные иды принадлежат числам. В частности, id 1 указывает на число 0, 3 указывает на 1, 5 точек на 2 и т.д.
Ответы
Ответ 1
В MRI объект object_id
объекта совпадает с VALUE
, который представляет объект на уровне C. Для большинства типов объектов этот VALUE
является указателем на местоположение в памяти, где хранятся фактические данные объекта. Очевидно, что это будет отличаться во время нескольких прогонов, потому что это зависит только от того, где система решила выделить память, а не на какое-либо свойство самого объекта.
Однако по соображениям производительности true
, false
, nil
и Fixnum
обрабатываются специально. Для этих объектов на самом деле нет структуры с данными объекта в памяти. Все данные объекта закодированы в самом VALUE
. Поскольку вы уже определили значения для false
, true
, nil
и любого Fixnum
i
, равны 0
, 2
, 4
и i*2+1
соответственно.
Причина, по которой это работает, заключается в том, что в любых системах, где работает MRI, 0
, 2
, 4
и i*2+1
никогда не являются действительными адресами для объекта в куче, поэтому нет совпадений с указателями для объектных данных.
Ответ 2
Назначение целых чисел (value * 2) + 1
и нецелых (x * 2)
аналогично парадокс Гильберта Гранд-отеля, в котором описывается, как назначать бесконечно больше гостей в бесконечный отель.
Что касается поиска объектов по их идентификатору, то ObjectSpace._id2ref(object_id)
. Если ваша реализация не имеет ObjectSpace.