Criar um objeto usando reflexão em vez de chamar o construtor de classe resulta em diferenças significativas de desempenho?
java
performance
optimization
reflection
dmanxiii
fonte
fonte
Respostas:
Sim absolutamente. Procurar uma classe via reflexão é, por magnitude , mais caro.
Citando a documentação do Java sobre reflexão :
Aqui está um teste simples que eu fiz em 5 minutos na minha máquina, executando o Sun JRE 6u10:
Com estes resultados:
Lembre-se de que a pesquisa e a instanciação são feitas juntas e, em alguns casos, a pesquisa pode ser refatorada, mas este é apenas um exemplo básico.
Mesmo se você apenas instanciar, ainda terá um impacto no desempenho:
Mais uma vez, YMMV.
fonte
Sim, é mais lento.
Mas lembre-se da maldita regra nº 1 - A otimização prematura é a raiz de todo o mal
(Bem, pode ser empatado com # 1 para DRY)
Juro que, se alguém viesse até mim no trabalho e me perguntasse isso, ficaria muito atento ao código deles nos próximos meses.
Você nunca deve otimizar até ter certeza de que precisa, até então, basta escrever um código legível e bom.
Ah, e também não quero escrever código estúpido. Basta pensar na maneira mais limpa possível de fazê-lo - sem copiar e colar, etc. (Ainda tenha cuidado com coisas como loops internos e usando a coleção que melhor se adapta às suas necessidades - Ignorar essas não é uma programação "não otimizada" , é "ruim" de programação)
Me assusta quando ouço perguntas como essa, mas depois esqueço que todo mundo precisa aprender todas as regras antes de realmente entender. Você o receberá depois de passar um mês depurando algo que alguém "Otimizou".
EDITAR:
Uma coisa interessante aconteceu neste tópico. Verifique a resposta nº 1, é um exemplo de quão poderoso o compilador é para otimizar as coisas. O teste é completamente inválido porque a instanciação não reflexiva pode ser completamente fatorada.
Lição? NUNCA otimize até escrever uma solução limpa e bem codificada e provar que é muito lenta.
fonte
Você pode achar que A a = new A () está sendo otimizado pela JVM. Se você colocar os objetos em uma matriz, eles não terão um desempenho tão bom. ;) As seguintes impressões ...
Isso sugere que a diferença é de cerca de 150 ns na minha máquina.
fonte
Class.getDeclaredMethod
) e depois ligarMethod.invoke
várias vezes? Estou usando a reflexão uma ou tantas vezes quanto a invoco? Pergunta de acompanhamento, e se, em vez dissoMethod
, for umConstructor
e eu fizerConstructor.newInstance
várias vezes?Se realmente houver necessidade de algo mais rápido que a reflexão e não for apenas uma otimização prematura, a geração de bytecode com ASM ou uma biblioteca de nível superior é uma opção. Gerar o bytecode pela primeira vez é mais lento do que apenas usar reflexão, mas depois que o bytecode foi gerado, ele é tão rápido quanto o código Java normal e será otimizado pelo compilador JIT.
Alguns exemplos de aplicativos que usam geração de código:
A chamada de métodos em proxies gerados pelo CGLIB é um pouco mais rápida que os proxies dinâmicos do Java , porque o CGLIB gera bytecode para seus proxies, mas os proxies dinâmicos usam apenas reflexão ( eu medi o CGLIB para ser cerca de 10x mais rápido nas chamadas de método, mas a criação dos proxies era mais lenta).
JSerial gera bytecode para ler / gravar os campos de objetos serializados, em vez de usar reflexão. Existem alguns benchmarks no site do JSerial.
Não tenho 100% de certeza (e não sinto vontade de ler a fonte agora), mas acho que o Guice gera bytecode para fazer a injeção de dependência. Corrija-me se eu estiver errado.
fonte
"Significativo" é inteiramente dependente do contexto.
Se você estiver usando a reflexão para criar um único objeto manipulador com base em algum arquivo de configuração e gastando o resto do seu tempo executando consultas no banco de dados, isso é insignificante. Se você estiver criando um grande número de objetos via reflexão em um loop apertado, sim, é significativo.
Em geral, a flexibilidade do projeto (quando necessário!) Deve direcionar o uso da reflexão, não do desempenho. No entanto, para determinar se o desempenho é um problema, é necessário criar um perfil, em vez de obter respostas arbitrárias em um fórum de discussão.
fonte
Há alguma sobrecarga na reflexão, mas é muito menor nas VMs modernas do que costumava ser.
Se você estiver usando a reflexão para criar todos os objetos simples do seu programa, algo está errado. Usá-lo ocasionalmente, quando você tiver um bom motivo, não deve ser um problema.
fonte
Sim, há um impacto no desempenho ao usar o Reflection, mas uma possível solução alternativa para otimização está armazenando em cache o método:
vai resultar em:
[java] O método de chamada 1000000 vezes reflexivamente com a pesquisa levou 5618 milis
[java] O método de chamada 1000000 vezes reflexivamente com o cache levou 270 milis
fonte
A reflexão é lenta, embora a alocação de objetos não seja tão desesperadora quanto outros aspectos da reflexão. Obter desempenho equivalente com instanciação baseada em reflexão exige que você escreva seu código para que o jit possa dizer qual classe está sendo instanciada. Se a identidade da classe não puder ser determinada, o código de alocação não poderá ser incorporado. Pior, a análise de escape falha e o objeto não pode ser alocado por pilha. Se você tiver sorte, a criação de perfil em tempo de execução da JVM poderá ser útil se esse código esquentar e determinar dinamicamente qual classe predomina e otimizar para essa.
Esteja ciente de que as marcas de microbench neste segmento são profundamente defeituosas, portanto, leve-as com um grão de sal. De longe, o menos defeituoso é o de Peter Lawrey: ele executa o aquecimento para obter os métodos executados e (conscientemente) derrota a análise de escape para garantir que as alocações estejam realmente ocorrendo. Mesmo que você tenha seus problemas, no entanto: por exemplo, pode-se esperar que um grande número de armazenamentos de array derrote caches e buffers de armazenamento, portanto, isso acabará sendo principalmente uma referência de memória se suas alocações forem muito rápidas. (Parabéns a Peter por ter chegado à conclusão certa: que a diferença é "150ns" em vez de "2,5x". Suspeito que ele faça esse tipo de coisa como meio de vida.)
fonte
Curiosamente, a definição de setAccessible (true), que ignora as verificações de segurança, tem uma redução de 20% no custo.
Sem setAccessible (true)
Com setAccessible (true)
fonte
1000000
invocações?setAccessible()
pode haver muito mais diferenças em geral, especialmente para métodos com vários argumentos, portanto, sempre deve ser chamado.Sim, é significativamente mais lento. Estávamos executando um código que fazia isso e, embora eu não tenha as métricas disponíveis no momento, o resultado final foi que tivemos que refatorar esse código para não usar reflexão. Se você souber qual é a classe, basta ligar diretamente para o construtor.
fonte
No doReflection () está a sobrecarga por causa de Class.forName ("misc.A") (que exigiria uma pesquisa de classe, potencialmente varrendo o caminho da classe no sistema de arquivos), em vez do newInstance () chamado na classe. Eu estou querendo saber como seriam as estatísticas se o Class.forName ("misc.A") for feito apenas uma vez fora do loop for, ele realmente não precisa ser feito para todas as chamadas do loop.
fonte
Sim, sempre será mais lento criar um objeto por reflexão, porque a JVM não pode otimizar o código no tempo de compilação. Veja os tutoriais Sun / Java Reflection para mais detalhes.
Veja este teste simples:
fonte
Class.forName()
) da instância (newInstance ()), porque elas variam significativamente em suas características de desempenho e, ocasionalmente, você pode evitar a pesquisa repetida em um sistema bem projetado.Freqüentemente, você pode usar o Apache commons BeanUtils ou PropertyUtils cuja introspecção (basicamente eles armazenam em cache os metadados sobre as classes para que eles nem sempre precisem usar a reflexão).
fonte
Eu acho que depende de quão leve / pesado o método de destino é. se o método de destino for muito leve (por exemplo, getter / setter), pode ser 1 a 3 vezes mais lento. se o método de destino demorar cerca de 1 milissegundo ou mais, o desempenho será muito próximo. aqui está o teste que fiz com o Java 8 e reflectasm :
O código de teste completo está disponível no GitHub: ReflectionTest.java
fonte