Будет ли.hashcode() возвращать другой int из-за сжатия пространства владения?

Если я позвоню Object.hashcode() Метод для некоторого объекта возвращает внутренний адрес объекта (реализация по умолчанию). Этот адрес является логическим или физическим адресом?

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

5 ответов

Решение

@erickson более или менее правильно. Хэш-код, возвращаемый java.lang.Object.hashCode() не изменяется за время существования объекта.

Способ, которым это (обычно) реализовано, довольно умный. Когда объект перемещается сборщиком мусора, его оригинальный хеш-код должен храниться где-то на случай, если он будет использован снова. Очевидный способ реализовать это - добавить 32-битное поле в заголовок объекта для хранения хеш-кода. Но это добавило бы 1 слово к каждому объекту и потратило бы место в наиболее распространенном случае... где объект hashCode метод не вызывается.

Решение состоит в том, чтобы добавить два бита флага к слову флага объекта и использовать их (примерно) следующим образом. Первый флаг устанавливается, когда hashCode метод называется. Второй флаг говорит hashCode метод, использовать ли текущий адрес объекта в качестве хеш-кода или использовать сохраненное значение. Когда GC запускается и перемещает объект, он проверяет эти флаги. Если первый флаг установлен, а второй не установлен, ГХ выделяет одно дополнительное слово в конце объекта и сохраняет исходное местоположение объекта в этом слове. Затем он устанавливает два флага. С тех пор, hashCode Метод получает значение хеш-кода из слова в конце объекта.


На самом деле, identityHashCode Реализация должна вести себя таким образом, чтобы удовлетворить следующую часть общего контракта hashCode:

"Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число, при условии, что никакая информация, используемая в сравнениях сравнения объекта, не изменяется. Это целое число не должно оставаться согласованным с одно исполнение приложения к другому исполнению того же приложения. "

Гипотетическая реализация identityHashCode() то, что просто вернуло текущий машинный адрес объекта, нарушило бы выделенную часть, если / когда ГХ переместил объект по другому адресу. Единственный способ обойти это (для гипотетической) JVM - гарантировать, что объект никогда не перемещается один раз. hashCode был призван на это. И это привело бы к серьезным и неразрешимым проблемам с фрагментацией кучи.

Нет, хеш-код объекта по умолчанию не изменится.

Документация не говорит, что хеш-код является адресом, она говорит, что она основана на адресе. Учтите, что хэш-коды 32-битные, но есть 64-битные JVM. Ясно, что непосредственное использование адреса не всегда будет работать.

Реализация зависит от JVM, но в JVM от Sun (Oracle) я считаю, что хэш-код кэшируется при первом обращении к нему.

По договору hashCode он не может измениться по такой причине.

В этой ссылке говорится, что действительно хеш-код по умолчанию - это адрес JVM объекта, но если он перемещается - адрес остается согласованным. Я не знаю, насколько надежен этот источник, но я уверен, что разработчики этого метода продумали этот сценарий (что не является редким или угловым случаем) и обеспечили правильную функциональность этого метода.

Если хеш-код изменится, объект исчезнет в хэш-наборе, в который он был вставлен, и Sun зальет жалобами.

Другие вопросы по тегам