Как Object.GetHashCode () реализован в CLR и JVM?

Я размышлял об этом некоторое время: как именно Object.GetHashCode реализован в CLR или Java? Контракт для этого метода заключается в том, что если он вызывается для одного и того же экземпляра объекта, он всегда должен возвращать одно и то же значение.

Обратите внимание, что я говорю о реализации GetHashCode () по умолчанию. Производные классы не обязаны переопределять этот метод. Если они решат этого не делать, они, по сути, будут иметь ссылочную семантику: равенство по умолчанию равно «равенству указателя» при использовании в хеш-таблицах и т. Д. Это означает, что каким-то образом среда выполнения должна предоставлять постоянный хэш-код для объекта на протяжении всего его жизненного цикла.

Если машина, на которой я работаю, 32-разрядная, и если экземпляр объекта никогда не перемещался в памяти, теоретически можно было бы вернуть адрес объекта, переинтерпретированный как Int32. Это было бы хорошо, поскольку все отдельные объекты имеют разные адреса и, следовательно, будут иметь разные хэш-коды.

Однако этот подход ошибочен, среди прочего, потому что:

  • если сборщик мусора перемещает объект в памяти, его адрес изменяется , а также его хэш-код в нарушение контракта о том, что хэш-код должен быть одинаковым на протяжении всего времени существования объекта.

  • В 64-битной системе адрес объекта слишком велик, чтобы поместиться в Int32.

  • Поскольку управляемые объекты обычно выравниваются по некоторой четной степени двойки, самые нижние биты всегда будут нулевыми. Это может вызвать неправильные шаблоны распределения, когда хэш-коды используются для индексации в хеш-таблице.

В .NET System.Object состоит из блока синхронизации и дескриптора типа и ничего более, поэтому хэш-код не может быть кэширован в самом экземпляре. Каким-то образом среда выполнения может предоставить постоянный хэш-код. Как? И как это делают Java, Mono и другие среды выполнения?

12
задан John Källén 7 April 2011 в 13:54
поделиться