Почему определение класса как final улучшает производительность JVM?

Цитата из http://sites.google.com/site/gson/gson-design-document:

Почему большинство занятий в Gson отмечены как финальные?

Хотя Gson предоставляет достаточно расширяемую архитектуру, предоставляя подключаемые сериализаторы и десериализаторы, классы Gson не были специально предназначены для расширения. Предоставление неокончательных классов позволило бы пользователю законно расширять классы Gson, а затем ожидать, что такое поведение будет работать во всех последующих версиях. Мы решили ограничить такие варианты использования, пометив классы как окончательные и дождавшись появления хорошего варианта использования, обеспечивающего расширяемость. Пометка класса как final также имеет небольшое преимущество, так как предоставляет дополнительные возможности оптимизации для компилятора Java и виртуальной машины.

Почему это так? [Если бы я мог предположить: JVM знает, что класс окончательный, он не поддерживает таблицы переопределения методов? Есть ли другие причины?]

Какая польза от производительности?

Применимо ли это к классам, экземпляры которых создаются с частотой (POJO?), Или, возможно, к классам, которые являются статическими методами-держателями (служебные классы)?

Могут ли методы, определенные как окончательные, теоретически улучшить производительность?

Есть ли какие-нибудь последствия?

Спасибо, Максим.


person Maxim Veksler    schedule 18.10.2010    source источник
comment
Я уверен, что если вы искали SO, вы найдете ответ на этот вопрос; Я помню одно всего несколько дней назад. Но, тем не менее, я рекомендую вам проигнорировать последнее предложение; остальная часть абзаца важна.   -  person Anon    schedule 18.10.2010
comment
Я прошу только для обучения. Хотелось бы получить ссылку, потому что я не нашел ее (провел быстрый поиск, прежде чем спрашивать).   -  person Maxim Veksler    schedule 18.10.2010
comment
Согласны, преимущество маркировки классов final больше связано с документированием их дизайна (или его отсутствия) с точки зрения расширяемости, чем с производительностью. (С другой стороны, @Maxim Veksler спросил не об этом ...)   -  person andersoj    schedule 18.10.2010
comment
Я не знаю относительно разумной JVM, которая пропускала бы CHA (анализ иерархии классов), поэтому окончательные классы ничего не улучшают.   -  person bestsss    schedule 03.09.2011
comment
Насколько я понимаю, оптимизацию final выполняет JIT, а не JVM. Подробнее см. в этой статье.   -  person b1nary.atr0phy    schedule 07.06.2013


Ответы (5)


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

Некоторые виртуальные машины (например, HotSpot) могут действовать более разумно и знать, когда методы переопределяются / не отменяются, и при необходимости генерировать более быстрый код.

Вот более конкретная информация о HotSpot. И немного общей информации.

person TofuBeer    schedule 18.10.2010

Старая, по-видимому, уже не , но все еще актуальная статья об этом от IBM developerWorks, в котором говорится:

Распространено мнение, что объявление классов или методов final упрощает компилятору встроенные вызовы методов, но это восприятие неверно (или, по крайней мере, сильно преувеличено).

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

Также см. Этот ответ на другой вопрос. Также есть эквивалентный вопрос для .Net, обсуждаемый здесь. Обсуждение SO, Встроены ли окончательные методы? На вопрос под названием Какие оптимизации будут бесполезны завтра, этот появится в списке.

Также обратите внимание на то, что существует переплетение эффектов final классов и final методов. Вы можете получить некоторый выигрыш в производительности (опять же, у меня нет хорошей ссылки) для final методов наверняка, так как это может дать команду JIT выполнить встраивание его не может ' В противном случае сделать (или не так просто). Вы получаете тот же эффект, когда вы отмечаете класс final, что означает, что все методы также внезапно становятся окончательными. Обратите внимание, что специалисты Sun / Oracle утверждают, что HotSpot обычно может делать это с ключевым словом final или без него. Есть ли какие-либо дополнительные эффекты от самого класса final?

Для справки, ссылки на JLS для методов final и final классы.

person andersoj    schedule 18.10.2010
comment
Это было правдой в ОЧЕНЬ старые времена. Когда мы ударяли по камням, чтобы получить единицы, нули и нули. - person Thorbjørn Ravn Andersen; 18.10.2010
comment
@ Thorbjørn: «Удар камнями» звучит намного продуктивнее, чем большая часть разработки программного обеспечения, которую я вижу ... ;-) Предположительно HotSpot делает все правильно - можем ли мы предположить, что все компиляторы Java и JVM наконец-то догнали? - person andersoj; 18.10.2010
comment
@andersoj, высокопроизводительные JVM должны делать это, чтобы получить достаточную скорость (торговля за память). Маленькие JVM, такие как JamVM, не могут выполнять столь агрессивную оптимизацию, чтобы оставаться небольшими, поэтому они не могут работать так же быстро. - person Thorbjørn Ravn Andersen; 18.10.2010
comment
@ Thorbjørn: Чтобы уточнить - компромисс между временем и пространством, о котором вы упоминаете, - это пространство для хранения встроенных фрагментов кода (по сравнению с эффективностью выполнения этого кода)? - person andersoj; 18.10.2010
comment
@andersoj. Нет, это пространство, необходимое JVM для собственных внутренних структур данных, описывающих выполняемую программу. По сути, чем больше вычислений вы запомните на будущее, тем более сложные преобразования программы вы сможете выполнить. - person Thorbjørn Ravn Andersen; 18.10.2010
comment
@ Thorbjørn: Ах, хорошо, это помогает. Я не фанат JVM, но, кажется, время от времени ругаюсь с людьми. Есть ли какие-то канонические нюансы ВМ, на которые стоит обратить внимание? - person andersoj; 19.10.2010
comment
@andersoj, я с одним не знаком. Кроме того, различные кодовые базы JVM сильно различаются, поэтому их сложно обобщить. У IBM Developerworks есть несколько хороших статей. - person Thorbjørn Ravn Andersen; 19.10.2010
comment
@ Thorbjørn: Открыл новый вопрос по этой теме: stackoverflow.com/questions/3963643/ - person andersoj; 19.10.2010

Не зная реализации каждой конкретной JVM, я бы теоретически сказал, что если JVM знает, что указатель на объект является указателем на тип, который является окончательным, она может выполнять невиртуальные вызовы функций (т. Е. Прямые или косвенные) к функциям-членам (т. е. отсутствие косвенного обращения через указатель функции), что может привести к более быстрому выполнению. Это также может, в свою очередь, привести к возможностям встраивания.

person Michael Goldshteyn    schedule 18.10.2010
comment
Sun JVM достаточно умен, чтобы, если подклассы не были загружены, она рассматривала методы базового класса как невиртуальные. - person Steve Kuo; 18.10.2010
comment
Да, но если это произойдет, ему также необходимо распознать, когда загружен новый подкласс, и принудительно перекомпилировать любой вызов - person Christopher Barber; 10.05.2012
comment
(продолжение - Кстати, насколько отстает то, что я не могу исправить свой комментарий?) ... метод базового класса, который был выведен как окончательный. JVM вряд ли будет отслеживать каждый такой метод, поэтому, вероятно, потребуется перекомпилировать все методы, которые вызывают любой из методов этого базового класса. - person Christopher Barber; 10.05.2012

Пометка классов как final позволяет применять дальнейшую оптимизацию на этапе JIT.

Если вы вызываете виртуальный метод неоконечного класса, вы не знаете, является ли правильная реализация той, которая определена в этом классе, или каким-то подклассом, о котором вы не знаете.

Однако, если у вас есть ссылка на последний класс, вы знаете, какая конкретная реализация требуется.

Учитывать:

A extends B
B extends C

B myInstance = null;
if(someCondition)
   myInstance = new B();
else
   myInstance = new C();
myInstance.toString();

В этом случае JIT не может знать, будет ли вызвана реализация toString () в C или реализация toString () B. Однако, если B помечено как окончательное, никакая реализация, кроме B, не может быть правильной реализацией.

person LorenVS    schedule 18.10.2010
comment
Есть ли документация о том, что HotSpot или другие крупные поставщики JVM используют это? Кто-нибудь недавно измерял эффект в производственном коде? - person andersoj; 18.10.2010
comment
JVM знает, есть ли подкласс, потому что отслеживает, какие классы были загружены. Если B и C никогда не загружаются, он знает, что все методы A могут быть вызваны напрямую. - person Steve Kuo; 18.10.2010

Без разницы, это просто домыслы. Единственная ситуация, в которой это имеет смысл, - это такие классы, как String и т. Д., Где jvm обрабатывает их по-разному.

person Stas    schedule 18.10.2010