Existe algum benefício de desempenho de uma forma ou de outra? É específico do compilador / VM? Estou usando o Hotspot.
java
performance
premature-optimization
Andy Faibishenko
fonte
fonte
Quatro anos depois...
Ok, na esperança de resolver essa questão de uma vez por todas, eu escrevi um benchmark que mostra como os diferentes tipos de chamadas (virtuais, não virtuais, estáticas) se comparam entre si.
Eu executei em um único , e isto é o que consegui:
(Quanto maior o número de iterações, melhor.)
Como esperado, as chamadas de métodos virtuais são as mais lentas, as chamadas de métodos não virtuais são mais rápidas e as chamadas de métodos estáticos são ainda mais rápidas.
O que eu não esperava era que as diferenças fossem tão pronunciadas: chamadas de método virtual foram medidas para rodar a menos da metade da velocidade de chamadas de método não virtuais, que por sua vez foram medidas para rodar 15% mais lento do que chamadas estáticas. É isso que essas medidas mostram; as diferenças reais devem ser um pouco mais pronunciadas, pois para cada chamada de método virtual, não virtual e estático, meu código de benchmarking tem uma sobrecarga constante adicional de incremento de uma variável inteira, verificação de uma variável booleana e loop se não for verdadeiro.
Suponho que os resultados variam de CPU para CPU e de JVM para JVM, então experimente e veja o que você obtém:
É importante notar que essa diferença de desempenho só se aplica ao código que não faz nada além de invocar métodos sem parâmetros. Qualquer outro código que você tenha entre as invocações diluirá as diferenças, e isso inclui a passagem de parâmetros. Na verdade, a diferença de 15% entre chamadas estáticas e não virtuais é provavelmente explicada por completo pelo fato de que o
this
ponteiro não precisa ser passado para o método estático. Portanto, seria necessário apenas uma pequena quantidade de código fazendo coisas triviais entre as chamadas para que a diferença entre os diferentes tipos de chamadas fosse diluída a ponto de não ter nenhum impacto na rede.Além disso, as chamadas de método virtual existem por um motivo; eles têm um propósito a servir e são implementados usando os meios mais eficientes fornecidos pelo hardware subjacente. (O conjunto de instruções da CPU.) Se, no seu desejo de eliminá-los substituindo-os por chamadas não virtuais ou estáticas, você acabar tendo que adicionar até um iota de código extra para emular sua funcionalidade, então sua sobrecarga líquida resultante é limitada ser não menos, mas mais. Muito possivelmente, muito, muito, incomensuravelmente muito, mais.
fonte
VirtualTest | 488846733 -- NonVirtualTest | 480530022 -- StaticTest | 484353198
na minha instalação do OpenJDK. FTR: Isso é verdade mesmo se eu remover ofinal
modificador. Btw. Tive que fazer oterminate
campovolatile
, senão a prova não acabou.VirtualTest | 12451872 -- NonVirtualTest | 12089542 -- StaticTest | 8181170
. Além do OpenJDK no meu notebook conseguir realizar 40x mais iterações, o teste estático sempre tem cerca de 30% menos throughput. Este pode ser um fenômeno específico da ART, porque obtenho um resultado esperado em um tablet Android 4.4:VirtualTest | 138183740 -- NonVirtualTest | 142268636 -- StaticTest | 161388933
Bem, as chamadas estáticas não podem ser substituídas (portanto, são sempre candidatas a inlining) e não exigem nenhuma verificação de nulidade. O HotSpot faz um monte de otimizações legais para métodos de instância que podem negar essas vantagens, mas são possíveis razões pelas quais uma chamada estática pode ser mais rápida.
No entanto, isso não deve afetar seu design - código da forma mais legível e natural - e apenas se preocupar com esse tipo de microotimização se tiver uma causa justa (o que você quase nunca terá).
fonte
É específico do compilador / VM.
Portanto, provavelmente não vale a pena se preocupar com isso, a menos que você tenha identificado isso como um problema de desempenho verdadeiramente crítico em seu aplicativo. A otimização prematura é a raiz de todos os males, etc ...
No entanto , vi essa otimização dar um aumento substancial de desempenho na seguinte situação:
Se o acima se aplica a você, pode valer a pena testar.
Há também uma outra razão boa (e potencialmente ainda mais importante!) Para usar um método estático - se o método realmente tiver semântica estática (ou seja, logicamente não está conectado a uma determinada instância da classe), então faz sentido torná-lo estático para refletir esse fato. Os programadores Java experientes então notarão o modificador estático e pensarão imediatamente "aha! Este método é estático, então não precisa de uma instância e presumivelmente não manipula o estado específico da instância". Portanto, você comunicou a natureza estática do método de forma eficaz ....
fonte
Como já disseram os pôsteres anteriores: Parece uma otimização prematura.
No entanto, há uma diferença (parte do fato de que as invocações não estáticas exigem um envio adicional de um objeto callee na pilha de operandos):
Como os métodos estáticos não podem ser substituídos, não haverá nenhuma pesquisa virtual no tempo de execução para uma chamada de método estático. Isso pode resultar em uma diferença observável em algumas circunstâncias.
A diferença em um nível de byte-code é que uma chamada de método não-estático é feito através de
INVOKEVIRTUAL
,INVOKEINTERFACE
ouINVOKESPECIAL
durante uma chamada de método estático é feito através deINVOKESTATIC
.fonte
invokespecial
uma vez que não é virtual.É inacreditavelmente improvável que qualquer diferença no desempenho de chamadas estáticas em relação às não estáticas esteja fazendo diferença em seu aplicativo. Lembre-se de que "a otimização prematura é a raiz de todos os males".
fonte
7 anos depois ...
Não tenho muita confiança nos resultados que Mike Nakis encontrou porque eles não abordam alguns problemas comuns relacionados às otimizações de pontos de acesso. Eu instrumentei benchmarks usando JMH e descobri que a sobrecarga de um método de instância é de cerca de 0,75% na minha máquina em comparação com uma chamada estática. Considerando a baixa sobrecarga, acho que, exceto nas operações mais sensíveis à latência, essa não é, sem dúvida, a maior preocupação no design de um aplicativo. Os resultados resumidos do meu benchmark JMH são os seguintes;
Você pode olhar o código aqui no Github;
https://github.com/nfisher/svsi
O benchmark em si é bastante simples, mas visa minimizar a eliminação de código morto e o dobramento constante. Possivelmente, há outras otimizações que perdi / negligenciei e esses resultados provavelmente variam de acordo com a versão da JVM e o SO.
fonte
ops/s
microotimização pode ter em métricas, exceto principalmente em um ambiente ART (por exemplo, uso de memória, tamanho de arquivo reduzido .oat, etc.). Você conhece alguma ferramenta / maneira relativamente simples de tentar avaliar essas outras métricas?Para a decisão se um método deve ser estático, o aspecto do desempenho deve ser irrelevante. Se você tiver um problema de desempenho, tornar muitos métodos estáticos não vai salvar o dia. Dito isso, os métodos estáticos quase certamente não são mais lentos do que qualquer método de instância, na maioria dos casos ligeiramente mais rápidos :
1.) Os métodos estáticos não são polimórficos, portanto, a JVM tem menos decisões a tomar para encontrar o código real a ser executado. Este é um ponto discutível no Age of Hotspot, uma vez que o Hotspot otimizará chamadas de método de instância que têm apenas um site de implementação, para que executem o mesmo.
2.) Outra diferença sutil é que os métodos estáticos obviamente não têm nenhuma referência "esta". Isso resulta em um quadro de pilha um slot menor do que o de um método de instância com a mesma assinatura e corpo ("this" é colocado no slot 0 das variáveis locais no nível de bytecode, enquanto para métodos estáticos o slot 0 é usado para o primeiro parâmetro do método).
fonte
Pode haver uma diferença, e pode ser de qualquer maneira para qualquer parte específica do código, e pode mudar até mesmo com um pequeno release da JVM.
Isso é definitivamente parte dos 97% de pequenas eficiências que você deve esquecer .
fonte
TableView
milhões de registros.Em teoria, menos caro.
A inicialização estática será feita mesmo se você criar uma instância do objeto, enquanto os métodos estáticos não farão nenhuma inicialização normalmente feita em um construtor.
No entanto, não testei isso.
fonte
Como Jon observa, os métodos estáticos não podem ser substituídos, então simplesmente invocar um método estático pode ser - em um Java runtime suficientemente ingênuo - mais rápido do que invocar um método de instância.
Mas então, mesmo supondo que você esteja no ponto em que se preocupa em bagunçar seu design para economizar alguns nanossegundos, isso apenas levanta outra questão: você precisará substituir o método por si mesmo? Se você alterar seu código para tornar um método de instância em um método estático para economizar um nanossegundo aqui e ali, e então virar e implementar seu próprio despachante em cima disso, o seu quase certamente será menos eficiente do que aquele construído em seu Java runtime já.
fonte
Eu gostaria de acrescentar às outras ótimas respostas aqui que também depende do seu fluxo, por exemplo:
Preste atenção ao criar um novo objeto MyRowMapper para cada chamada.
Em vez disso, sugiro usar aqui um campo estático.
fonte