Есть ли какой-то выигрыш в производительности так или иначе? Это конкретный компилятор / виртуальная машина? Я использую точку доступа.
java
performance
premature-optimization
Энди Файбишенко
источник
источник
Четыре года спустя...
Хорошо, в надежде решить этот вопрос раз и навсегда, я написал тест, который показывает, как разные типы вызовов (виртуальные, не виртуальные, статические) сравниваются друг с другом.
Я запустил его на ideone , и вот что у меня получилось:
(Лучше большее количество итераций.)
Как и ожидалось, вызовы виртуальных методов являются самыми медленными, вызовы не виртуальных методов выполняются быстрее, а вызовы статических методов еще быстрее.
Чего я не ожидал, так это того, что различия будут настолько заметными: вызовы виртуальных методов, по измерениям, выполнялись на уровне менее половины скорости вызовов невиртуальных методов, которые, в свою очередь, выполнялись на целых 15% медленнее, чем статические вызовы. Вот что показывают эти измерения; Фактические различия должны быть немного более выраженными, поскольку для каждого вызова виртуального, невиртуального и статического метода мой тестовый код имеет дополнительные постоянные накладные расходы, связанные с увеличением одной целочисленной переменной, проверкой логической переменной и зацикливанием, если не истинно.
Я полагаю, что результаты будут отличаться от процессора к процессору и от JVM к JVM, поэтому попробуйте и посмотрите, что вы получите:
Стоит отметить, что эта разница в производительности применима только к коду, который не делает ничего, кроме вызова методов без параметров. Любой другой код, который у вас есть между вызовами, уменьшит различия, включая передачу параметров. На самом деле, разница в 15% между статическими и невиртуальными вызовами, вероятно , объясняется в полной мере тем , что
this
указатель не должен быть передан статическим метод. Таким образом, потребовалось бы лишь довольно небольшое количество кода, выполняющего тривиальные вещи между вызовами, чтобы разница между различными типами вызовов уменьшилась до такой степени, что не оказало никакого общего влияния.Кроме того, вызовы виртуальных методов существуют не просто так; у них действительно есть цель, и они реализуются с использованием наиболее эффективных средств, предоставляемых базовым оборудованием. (Набор инструкций ЦП.) Если, желая устранить их, заменив их невиртуальными или статическими вызовами, вам в конечном итоге придется добавить не меньше йоты дополнительного кода для имитации их функциональности, тогда ваши итоговые чистые накладные расходы будут ограничены быть не меньше, а больше. Вполне возможно, намного, намного, непостижимо много, больше.
источник
VirtualTest | 488846733 -- NonVirtualTest | 480530022 -- StaticTest | 484353198
на моей установке OpenJDK. FTR: Это даже правда, если я уберуfinal
модификатор. Кстати. Пришлось пройтиterminate
полеvolatile
, иначе тест не закончился.VirtualTest | 12451872 -- NonVirtualTest | 12089542 -- StaticTest | 8181170
. Мало того, что OpenJDK на моем ноутбуке удается выполнить в 40 раз больше итераций, статический тест всегда дает примерно на 30% меньше пропускной способности. Это может быть специфическое явление ART, потому что я получаю ожидаемый результат на планшете Android 4.4:VirtualTest | 138183740 -- NonVirtualTest | 142268636 -- StaticTest | 161388933
Что ж, статические вызовы не могут быть переопределены (поэтому всегда являются кандидатами на встраивание) и не требуют никаких проверок на нулевое значение. HotSpot выполняет кучу классных оптимизаций, например, методов, которые могут свести на нет эти преимущества, но это возможные причины, по которым статический вызов может быть быстрее.
Однако это не должно влиять на ваш дизайн - код наиболее читаемым и естественным образом - и беспокоиться о такого рода микрооптимизации только в том случае, если у вас есть веская причина (чего вы почти никогда не будете).
источник
Это зависит от компилятора / виртуальной машины.
Следовательно, вероятно, не стоит беспокоиться, если вы не определили это как действительно критическую проблему производительности в вашем приложении. Преждевременная оптимизация - это корень всех зол и т. Д.
Однако я уже видел это оптимизация дает существенное увеличение производительности в следующей ситуации:
Если вышесказанное относится к вам, возможно, стоит попробовать.
Есть также еще одна хорошая (и потенциально даже более важная!) Причина использовать статический метод - если метод действительно имеет статическую семантику (т.е. логически не связан с данным экземпляром класса), то имеет смысл сделать его статическим. чтобы отразить этот факт. Тогда опытные Java-программисты заметят модификатор static и сразу же подумают: «Ага! Этот метод статический, поэтому ему не нужен экземпляр и, по-видимому, он не управляет состоянием конкретного экземпляра». Таким образом, вы эффективно передадите статический характер метода ...
источник
Как говорилось на предыдущих плакатах: это похоже на преждевременную оптимизацию.
Однако есть одно отличие (отчасти из-за того, что нестатические вызовы требуют дополнительного проталкивания вызываемого объекта в стек операндов):
Поскольку статические методы нельзя переопределить, во время выполнения не будет никаких виртуальных поисков для вызова статического метода. При некоторых обстоятельствах это может привести к заметной разнице.
Разница на уровне байт-кода является то , что не-статический метод вызова выполняется через
INVOKEVIRTUAL
,INVOKEINTERFACE
или вINVOKESPECIAL
то время как статический метод вызова выполняется черезINVOKESTATIC
.источник
invokespecial
поскольку он не является виртуальным.Маловероятно, что какое-либо различие в производительности статических и нестатических вызовов имеет значение для вашего приложения. Помните, что «преждевременная оптимизация - корень всех зол».
источник
7 лет спустя ...
Я не очень уверен в результатах, которые нашел Майк Накис, потому что они не решают некоторые общие проблемы, связанные с оптимизацией Hotspot. Я инструментировал тесты с помощью JMH и обнаружил, что накладные расходы на метод экземпляра на моей машине составляют около 0,75% по сравнению со статическим вызовом. Учитывая эти низкие накладные расходы, я думаю, за исключением наиболее чувствительных к задержкам операций, это, возможно, не самая большая проблема при разработке приложений. Сводные результаты моего теста JMH следующие:
Вы можете посмотреть код здесь, на Github;
https://github.com/nfisher/svsi
Сам по себе тест довольно прост, но направлен на минимизацию устранения мертвого кода и постоянного сворачивания. Возможно, есть и другие оптимизации, которые я пропустил / упустил из виду, и эти результаты, вероятно, будут различаться в зависимости от выпуска JVM и ОС.
источник
ops/s
микрооптимизация может иметь для показателей, отличных от основных в среде ART (например, использование памяти, уменьшенный размер файла .oat и т. Д.). Знаете ли вы какие-либо относительно простые инструменты / способы, которыми можно было бы попытаться сравнить эти другие показатели?Для решения, должен ли метод быть статическим, аспект производительности не должен иметь значения. Если у вас проблемы с производительностью, создание статических методов не спасет положение. Тем не менее, статические методы почти наверняка не медленнее, чем любой метод экземпляра, в большинстве случаев немного быстрее :
1.) Статические методы не являются полиморфными, поэтому JVM должна принимать меньше решений, чтобы найти фактический код для выполнения. Это спорный вопрос в Age of Hotspot, поскольку Hotspot оптимизирует вызовы методов экземпляра, которые имеют только один сайт реализации, поэтому они будут работать одинаково.
2.) Еще одно тонкое отличие состоит в том, что у статических методов явно нет ссылки this. В результате кадр стека на один слот меньше, чем у метода экземпляра с той же сигнатурой и телом ("this" помещается в слот 0 локальных переменных на уровне байт-кода, тогда как для статических методов слот 0 используется для первого параметр метода).
источник
Может быть разница, и она может повлиять на любой конкретный фрагмент кода, и она может измениться даже с незначительным выпуском JVM.
Это определенно часть из 97% небольших показателей эффективности, о которых вам следует забыть .
источник
TableView
миллионах записей.Теоретически дешевле.
Статическая инициализация будет выполняться, даже если вы создаете экземпляр объекта, тогда как статические методы не будут выполнять никакой инициализации, обычно выполняемой в конструкторе.
Однако я этого не проверял.
источник
Как отмечает Джон, статические методы нельзя переопределить, поэтому простой вызов статического метода может быть - в достаточно наивной среде выполнения Java - быстрее, чем вызов метода экземпляра.
Но тогда, даже если предположить, что вы находитесь в той точке, где вы беспокоитесь о том, чтобы испортить свой дизайн, чтобы сэкономить несколько наносекунд, это просто поднимает другой вопрос: понадобится ли вам метод, переопределяющий себя? Если вы измените свой код, чтобы превратить метод экземпляра в статический метод, чтобы сэкономить наносекунду здесь и там, а затем развернитесь и внедрите свой собственный диспетчер поверх этого, ваш почти наверняка будет менее эффективным, чем созданный уже в вашу среду выполнения Java.
источник
Я хотел бы добавить к другим отличным ответам здесь, что это также зависит от вашего потока, например:
Обратите внимание, что вы создаете новый объект MyRowMapper для каждого вызова.
Вместо этого я предлагаю использовать здесь статическое поле.
источник