Java é realmente lento?

180

Java tem algum grau de reputação por ser lento .

  • Java é realmente lento?
  • Se sim, por que? Onde está (ou estava) o gargalo? É por causa de JVMs ineficientes? Coleta de lixo? Bibliotecas de bytecode puro em vez de código C envolto em JNI? Muitos outros idiomas têm esses recursos, mas eles não têm essa reputação de lentidão.
Stefano Borini
fonte
35
as pessoas ficam tão nervosas ... não vêem como isso pode ser subjetivo, nem argumentativo. Gostaria de saber se uma pergunta como "por que a classificação das bolhas é lenta" obteria o mesmo resultado. Fiz uma pergunta técnica e queria respostas técnicas (que recebi), mas fechar a pergunta como subjetiva e argumentativa é ridículo.
Stefano Borini
1
Eu li a maioria dos comentários principais e nenhum deles parece abordar o fato evidente de que os aplicativos de desktop baseados em GU # C # são executados muito mais rapidamente do que qualquer aplicativo de desktop baseado em GUI Java, incluindo os modernos.
BobTurbo 10/09
3
Como um desenvolvedor web do lado do cliente que lidou com formulários da web .net, .net MVC, PHP, Rails, Django e uma grande variedade de tudo, exceto o Spring (que eu ouvi dizer que é bom) em Java, espero um desempenho / arquitetura ruim de back-ends criados por equipes Java. Suspeito que o problema real não seja referência, mas a questão de simplesmente haver uma porcaria de desenvolvedores Java medíocres por aí. Isso não é culpa da linguagem. Não é culpa dos desenvolvedores Java que realmente aprimoram suas habilidades e aprendem outras linguagens além do Java. No entanto, pode ser culpa da Sun, da empresa, dos anos 90 e do setor de TI em geral.
precisa saber é o seguinte

Respostas:

236

O Java moderno é uma das linguagens mais rápidas, apesar de ainda ser um porco da memória. O Java tinha a reputação de ser lento porque costumava demorar muito tempo para a VM iniciar.

Se você ainda acha que o Java é lento , consulte os resultados do jogo de benchmarks . Um código altamente otimizado, escrito em uma linguagem compilada antecipadamente (C, Fortran, etc.) pode superá-lo; no entanto, Java pode ser mais do que 10x mais rápido que PHP, Ruby, Python, etc. Existem áreas específicas nas quais ele pode superar linguagens compiladas comuns (se usarem bibliotecas padrão).

Não há desculpa para aplicativos Java "lentos" agora. Os desenvolvedores e as bibliotecas / códigos herdados são os culpados, muito mais do que o idioma. Além disso, culpe qualquer coisa 'empresa'.

Para ser justo com o público "Java é lento", aqui estão as áreas em que ainda é lento (atualizado para 2013):

  • As bibliotecas geralmente são escritas para "correção" e legibilidade, não desempenho. Na minha opinião, esse é o principal motivo pelo qual o Java ainda tem uma má reputação, principalmente no lado do servidor. Isso torna os problemas de String exponencialmente piores. Alguns erros simples são comuns: os objetos são frequentemente usados ​​no lugar de primitivos, reduzindo o desempenho e aumentando o uso de memória. Muitas bibliotecas Java (incluindo as padrão) criarão Strings frequentemente, em vez de reutilizar formatos mutáveis ​​ou mais simples (char [] ou StringBuffer). Isso é lento e cria toneladas de lixo para coletar mais tarde. Para corrigir isso, sugiro que os desenvolvedores usem coleções primitivas e especialmente as bibliotecas da Javalution, sempre que possível.

  • As operações de string são um pouco lentas. Java usa objetos de sequência imutáveis codificados em UTF-16 . Isso significa que você precisa de mais memória, mais acesso à memória e algumas operações são mais complexas do que com ASCII (C, C ++). Na época, era a decisão certa para portabilidade, mas carrega um pequeno custo de desempenho. O UTF-8 parece uma escolha melhor agora.

  • O acesso à matriz é um pouco mais lento em comparação com C, devido a verificações de limites. A penalidade costumava ser grande, mas agora é pequena (o Java 7 otimiza muitas verificações de limites redundantes).

  • A falta de acesso arbitrário à memória pode tornar lento o processamento de E / S e o nível de bits (compactação / descompactação, por exemplo). Este é um recurso de segurança da maioria dos idiomas de alto nível agora.

  • Java usa MUITO mais memória que C e , se seu aplicativo estiver vinculado à memória ou à largura de banda da memória (cache, etc.), isso o tornará mais lento. O outro lado é que a alocação / desalocação é rápida (altamente otimizada). Este é um recurso da maioria das linguagens de alto nível agora, e devido a objetos e uso do GC em vez de alocação de memória explícita. Além de decisões ruins na biblioteca.

  • A E / S baseada em fluxos é lenta devido à (IMO, má escolha) exigir sincronização em cada acesso ao fluxo. NIO corrigiu isso, mas é uma dor de usar. Pode-se contornar isso fazendo leitura / gravação em uma matriz, em vez de um elemento de cada vez.

  • O Java não fornece a mesma funcionalidade de baixo nível que C, portanto , você não pode usar truques sujos de montador em linha para acelerar algumas operações. Isso fornece portabilidade e é um recurso da maioria dos idiomas de alto nível agora.

  • É comum ver aplicativos Java vinculados a versões muito antigas da JVM. Especialmente do lado do servidor. Essas antigas JVMs podem ser incrivelmente ineficientes, em comparação com as versões mais recentes.

No final, o Java foi projetado para fornecer segurança e portabilidade às custas de algum desempenho e para algumas operações realmente exigentes. A maior parte de sua reputação de lentidão não é mais merecida.


No entanto, existem vários lugares em que o Java é mais rápido que a maioria das outras linguagens:

  • A alocação e desalocação de memória são rápidas e baratas. Vi casos em que é 20% MAIS RÁPIDO (ou mais!) Alocar uma nova matriz de vários kB do que reutilizar uma em cache.

  • A instanciação de objetos e os recursos orientados a objetos são extremamente rápidos de usar (mais rápidos que o C ++ em alguns casos), porque foram criados desde o início. Isso é parcialmente devido à boa GC, e não à alocação explícita (que é mais amigável para muitas alocações de objetos pequenos). É possível codificar C que supera isso (rolando o gerenciamento de memória personalizado e fazendo malloc com eficiência), mas não é fácil.

  • As chamadas de método são basicamente gratuitas e, em alguns casos, mais rápidas que o código de método grande. O compilador HotSpot usa informações de execução para otimizar chamadas de métodos e possui inlining muito eficientes. Ao usar as informações adicionais de execução, algumas vezes pode superar os compiladores antecipados e até (em casos raros) a inserção manual. Compare com o C / C ++, onde as chamadas de método vêm com uma pequena penalidade de desempenho se o compilador decidir não alinhar.

  • Sincronização e multiencadeamento são fáceis e eficientes. O Java foi projetado para reconhecer o encadeamento desde o início e mostra. Os computadores modernos geralmente apresentam vários núcleos e, como o encadeamento é incorporado ao idioma, você pode tirar vantagem facilmente. Basicamente, um aumento extra de velocidade de 100% a 300% em comparação com o código C padrão de thread único. Sim, bibliotecas e encadeamentos C cuidadosamente escritos podem superar isso, mas é muito trabalho extra para o programador.

  • As seqüências incluem comprimento: algumas operações são mais rápidas. Isso supera o uso de seqüências delimitadas por nulo (comum em C). No Java 7, a Oracle retirou a otimização String.subString (), porque as pessoas a estavam usando estupidamente e obtendo vazamentos de memória.

  • A cópia da matriz é altamente otimizada. Nas versões mais recentes, o Java usa o assembler ajustado manualmente para System.arraycopy. O resultado é que, em operações com arraycopy / heavy de memcopy, vi meu código superar o equivalente em C por margens razoáveis.

  • O compilador JIT é inteligente sobre o uso do cache L1 / L2 . Os programas compilados antecipadamente não podem ajustar seu código em tempo real para a CPU e o sistema específicos em que estão sendo executados. O JIT fornece algumas transformações de loop muito eficientes dessa maneira.

Alguns outros fatos históricos contribuíram para a reputação "Java is slow":

  • Antes da compilação JIT (Java 1.2 / 1.3), a linguagem era apenas interpretada, não compilada e, portanto, muito lenta.
  • A compilação JIT levou tempo para se tornar eficiente (grandes melhorias em cada versão)
  • O carregamento de classes tornou-se muito mais eficiente ao longo dos anos. Costumava ser ineficiente e lento durante a inicialização.
  • Os códigos Swing e UI não usavam muito bem o hardware gráfico nativo.
  • Swing é simplesmente horrível. Eu culpo o AWT e o Swing pelo motivo pelo qual o Java nunca pegou o desktop.
  • Uso intenso de sincronização nas classes da biblioteca; versões não sincronizadas estão agora disponíveis
  • Os applets levam uma eternidade para carregar, devido à transmissão de um JAR completo pela rede e ao carregamento da VM para inicializar.
  • Sincronização usada para suportar uma penalidade de alto desempenho (isso foi otimizado com cada versão do Java). A reflexão ainda é cara, no entanto.
BobMcGee
fonte
49
Object instantiation and object-oriented features are blazing fast to use (faster than C++ in many cases) because they're designed in from the beginning.e Collections are fast. Standard Java beats standard C/C++ in this area, even for most optimized C code.são reivindicações selvagens não suportadas por qualquer evidência vinculada aqui.
Sjoerd
8
@ Sjoerd - As afirmações dificilmente são loucas - são óbvias para mim e devem ser para quem entende as diferenças na arquitetura do sistema de memória padrão em C / C ++ vs. Java. Você pode melhorar ainda mais se escrever seus próprios manipuladores de memória (com itens como listas gratuitas, conjuntos de memórias etc.) ou usar uma biblioteca que os implemente.
Rex Kerr #
15
@Rex Kerr - Por que usar manipuladores de memória se você pode usar, por exemplo, a pilha para alocação ?! Você está confundindo alocação de memória heap com instanciação de objeto.
Sjoerd
20
@Rex Kerr - Basicamente, você está afirmando que, como tudo em Java envolve alocar memória no heap, e como a alocação de Java no heap em Java é mais rápida que a de C ++, tudo em Java é mais rápido. Aqui estão algumas novidades para você: em C ++, você pode fazer sem alocar memória na pilha em muitos casos!
Sjoerd
10
@ Sjoerd - Onde eu disse que tudo em Java é mais rápido? Basta ler o que eu disse. Eu disse o que quis dizer e já falei de tudo o que você disse em seu último comentário.
Rex Kerr #
49

Inicialmente, o Java não era particularmente rápido, mas também não era muito lento. Hoje em dia, o Java é muito rápido. Das pessoas com quem conversei, a impressão de que o Java é lento vem de duas coisas:

  1. Tempo de inicialização lento da VM. A implementação inicial do Java levou muito tempo para iniciar e carregar as bibliotecas necessárias e o aplicativo em comparação com os aplicativos nativos.

  2. UI lenta. O balanço inicial foi lento. Provavelmente, não ajudou que a maioria dos usuários do Windows também considerasse o Metal L&F padrão feio.

Tendo em conta os pontos acima, não é de admirar que as pessoas tenham a impressão 'Java é lento'.

Para usuários ou desenvolvedores acostumados a desenvolver aplicativos nativos, ou mesmo aplicativos do Visual Basic , esses dois pontos são a coisa mais visível em um aplicativo, e é a primeira impressão que você terá sobre um aplicativo (a menos que seja um aplicativo não GUI no qual caso apenas o 1. se aplica.).

Você não convencerá um usuário de que "ele executa código muito rapidamente" quando o aplicativo leva 8 segundos para iniciar, em comparação com o aplicativo antigo do Visual Basic que é iniciado imediatamente - mesmo que a execução do código e o tempo de inicialização possam não estar conectados.

Arruinar a primeira impressão é uma ótima maneira de começar rumores e mitos. E rumores e mitos são difíceis de matar.

Em resumo, o Java não é lento. As pessoas com a "atitude Java é lenta" são baseadas nas primeiras impressões do Java há mais de 10 anos.

n
fonte
3
O Java ficou muito lento alguns anos atrás, mas em recentes testes de benchmark ele é executado quase tão rápido quanto o C / C ++ e, em algumas situações, é mais rápido.
ChadNC
23
Os aplicativos Java no OSX 10.6 no meu Macbook iniciam muito mais lentamente que os aplicativos escritos no Objective-C. Que evidência de tempos de inicialização rápidos?
Zan Lynx
2
Descompressão não é absolutamente um problema de desempenho. Meu computador, em 1992, descompactou os executáveis ​​ao iniciar programas que melhoravam o desempenho ao carregar um arquivo mais longo do disco rígido. A disparidade entre CPU e disco rígido aumentou enormemente nos últimos anos. No entanto, há um problema com o uso do formato de arquivo zip para rt.jar (por que? !!!) e os arquivos de classe contidos não estão vinculados (porcas !!).
Tom Hawtin - defina
5
@Zan: observe que a JVM para Mac OS X foi escrita (ou pelo menos adaptada) pela Apple. A Sun investiu bastante tempo para acelerar os tempos de inicialização nas plataformas suportadas (Windows, Linux e Solaris), mas não o fizeram no Mac OS x (já que não mantêm essa porta). Pode ser que Mac não poderia / não aplicar / porta todas essas otimizações mais para Mac OS X.
Joachim Sauer
1
Não considero o java lento (eu sei de um criador de jogos que faz jogos neles); ruim por motivos de interface do usuário. Nem um único aplicativo java "regular" que eu vi possui uma interface decente e completamente funcional.
RCIX 02/02
40

Depois de ler uma página cheia de comentários dizendo que o Java não é lento, só preciso responder com uma opinião diferente.

A lentidão de um idioma depende muito de quais são suas expectativas para 'rápido'. Se você considera o C # rápido, o Java certamente também é rápido. Se o domínio do problema estiver relacionado a bancos de dados ou processamento semi-em tempo real, o Java certamente também será rápido o suficiente. Se você está satisfeito em escalar seu aplicativo adicionando mais hardware, o Java provavelmente é rápido para você. Se você considerar que um fator constante de aceleração na escala de 5 a 10 não vale a pena, provavelmente considera o Java rápido.

Se você fizer computação numérica em grandes conjuntos de dados ou estiver vinculado a um ambiente de execução, onde os recursos da CPU são limitados, uma velocidade constante na escala de 5 a 10 seria enorme. Mesmo uma aceleração de 0,5 pode significar uma redução de 500 horas para o cálculo ser concluído. Nesses casos, o Java simplesmente não permite que você obtenha esse último quintal de desempenho e você provavelmente consideraria o Java lento.

Sami
fonte
2
concordou, e +1 em todo o post porque você apresenta um ponto válido, no entanto, o C ++, por exemplo, tem a fama diferente de ser difícil de depurar e fácil de tirar toda a perna, mas raramente ouvi falar que o C ++ era lento tanto como eu ouvi sobre java.
Stefano Borini 03/02
33

Você parece estar fazendo duas perguntas bastante diferentes:

  1. O Java é realmente lento? Em caso afirmativo, por que?
  2. Por que o Java é percebido como lento, mesmo que seja mais rápido do que muitas alternativas?

A primeira delas é mais ou menos um tipo de pergunta "quanto tempo dura uma corda". Tudo se resume à sua definição de "lento". Comparado a um intérprete puro, o Java é extremamente rápido. Comparado a outras linguagens que são (normalmente) compiladas para algum tipo de código de código e compiladas dinamicamente para código de máquina (por exemplo, C # ou qualquer outra coisa no .NET), o Java é praticamente o mesmo. Comparado às linguagens normalmente compiladas em código de máquina puro e com equipes (geralmente grandes) de pessoas trabalhando apenas para melhorar seus otimizadores (por exemplo, C, C ++, Fortran, Ada), o Java se sai muito bem em algumas coisas, mas no geral tende a ser pelo menos um pouco mais lento.

Muito disso está relacionado principalmente à implementação - basicamente, tudo se resume ao fato de um usuário aguardar enquanto um compilador dinâmico / JIT é executado. Portanto, a menos que você tenha um programa que seja executado por um bom tempo, é É difícil justificar que o compilador gaste muito tempo em otimizações difíceis. Portanto, a maioria dos compiladores Java (e C # etc.) não se esforçam muito em otimizações realmente difíceis. Em muitos casos, trata-se menos de quais otimizações são feitas do que onde elas são aplicadas. Muitos problemas de otimização são NP completos, portanto, o tempo gasto aumenta rapidamente com o tamanho do problema sendo atacado. Uma maneira de manter o tempo dentro da razão é aplicar apenas a otimização a algo como uma única função de cada vez. Quando é apenas o desenvolvedor aguardando o compilador, você pode demorar muito mais tempo e aplicar a mesma otimização a partes muito maiores do programa. Da mesma forma, o código para algumas otimizações é bastante cabeludo (e, portanto, pode ser bem grande). Novamente, como o usuário está aguardando enquanto o código é carregado (e o tempo de inicialização da JVM geralmente é um fator significativo no tempo geral), a implementação precisa equilibrar o tempo economizado em um local versus perdido em outro - e considerando o pouco código se beneficia das otimizações peludas, manter a JVM pequena geralmente é mais benéfica.

Um segundo problema é que, com Java, você freqüentemente obtém um tipo de solução mais ou menos "tamanho único". Apenas por exemplo, para muitos desenvolvedores Java, o Swing é essencialmente a única biblioteca de janelas disponível. Em algo como o C ++, existem literalmente dezenas de bibliotecas, estruturas de aplicativos etc., cada uma com seu próprio conjunto de compromissos entre facilidade de uso x execução rápida, aparência consistente versus aparência nativa, e assim por diante. O único ponto de discórdia real é que alguns (por exemplo, Qt) podem ser bastante caros (pelo menos para uso comercial).

Terceiro, muito código escrito em C ++ (e C ainda mais) é simplesmente mais antigo e mais maduro. Muitas delas contêm um núcleo de rotinas escritas décadas atrás, quando gastar tempo extra otimizando o código era um comportamento normal e esperado. Isso geralmente tem um benefício real em códigos menores e mais rápidos. C ++ (ou C) recebe o crédito pelo código ser pequeno e rápido, mas é realmente muito mais um produto do desenvolvedor e as restrições de quando o código foi escrito. Até certo ponto, isso leva a uma profecia auto-realizável - quando as pessoas se preocupam com a velocidade, geralmente selecionam C ++ porque ela tem essa reputação. Eles investem tempo e esforço extras na otimização e uma nova geração de código C ++ rápido é gravada.

Para resumir, a implementação normal de Java torna a otimização máxima problemática, na melhor das hipóteses. Pior, onde Java é visível , coisas como kits de ferramentas de janelas e tempo de inicialização da JVM geralmente desempenham um papel maior do que a velocidade de execução da própria linguagem. Em muitos casos, C e C ++ também recebem crédito pelo que é realmente o produto de simplesmente trabalhar mais na otimização.

Quanto à segunda pergunta, acho que é em grande parte uma questão da natureza humana em ação. Alguns fanáticos fazem afirmações bastante infladas sobre o Java ser incrivelmente rápido. Alguém experimenta e descobre que mesmo um programa trivial leva alguns segundos para começar e se sente lento e desajeitado quando é executado. Poucos provavelmente se incomodam em analisar as coisas para perceber que grande parte disso é o tempo de inicialização da JVM e o fato de que, quando tentam, nada do código foi compilado ainda - parte do código está sendo interpretado, e alguns sendo compilados enquanto esperam. Pior, mesmo quando é executado com rapidez suficiente, a aparência e a aparência geralmente parecem estranhas e desajeitadas para a maioria dos usuários; portanto, mesmo que as medidas objetivas mostrem tempos de resposta rápidos, ainda pareceria desajeitado.

A adição desses elementos leva a uma reação bastante simples e natural: o Java é lento, feio e desajeitado. Dado o hype de dizer que é realmente rápido, há uma tendência a reagir exageradamente e concluir que isso é horrivelmente lento, em vez de um (mais preciso) "um pouco mais lento, e principalmente em circunstâncias específicas". Isso geralmente é o pior para um desenvolvedor que escreve os primeiros programas no idioma. A execução de um programa "olá mundo" na maioria dos idiomas parece instantânea, mas em Java há uma pausa facilmente perceptível quando a JVM é iniciada. Mesmo um intérprete puro que executa muito mais devagar em loops apertados e ainda assim parece mais rápido para códigos como esse, simplesmente porque ele pode ser carregado e começar a executar um pouco mais cedo.

Jerry Coffin
fonte
16

São informações desatualizadas dos primeiros dias (meados da década de 90) do Java. Todas as principais versões do Java introduziram acelerações significativas em comparação com a versão anterior. Com o Oracle aparentemente mesclando o JRockit com o JVM da Sun para Java 7, essa tendência parece continuar.

Comparado a muitas outras linguagens modernas populares (Python, Ruby, PHP), o Java é realmente significativamente mais rápido para a maioria dos usos. Não corresponde exatamente a C ou C ++, mas para muitas tarefas é próximo o suficiente. As preocupações reais de desempenho devem ser sobre quanta memória ela acaba usando.

Dan Dyer
fonte
14

O principal culpado no "longo tempo de inicialização" é a vinculação dinâmica. Um aplicativo Java consiste em classes compiladas. Cada classe faz referência a outras classes (para tipos de argumentos, invocações de métodos ...) pelo nome . A JVM deve examinar e corresponder a esses nomes na inicialização. Faz isso de forma incremental, fazendo apenas as partes necessárias em um determinado momento, mas ainda há trabalho a fazer.

Em um aplicativo C, essa fase de vinculação ocorre no final da compilação. É lento, especialmente para grandes aplicativos, mas apenas o desenvolvedor vê. A vinculação gera um arquivo executável que o sistema operacional simplesmente precisa carregar na RAM "como está".

Em Java, a vinculação ocorre toda vez que o aplicativo é executado. Daí o longo tempo de inicialização.

Várias otimizações foram aplicadas, incluindo técnicas de armazenamento em cache, e os computadores ficam mais rápidos (e ficam "mais rápidos" do que os aplicativos "maiores"); portanto, a importância do problema diminuiu muito recentemente; mas o velho preconceito permanece.

Quanto ao desempenho posterior, meus próprios benchmarks em cálculos compactos com acesso a array (principalmente funções hash e outros algoritmos criptográficos) geralmente mostram que o código C otimizado é cerca de 3x mais rápido que o código Java; às vezes C é apenas 30% mais rápido que Java, às vezes C pode ser 4x mais rápido, dependendo do algoritmo implementado. Vi um fator 10x quando o código "C" era realmente montado para grandes aritméticas inteiras, devido aos opcodes de multiplicação 64x64-> 128 que o processador oferece, mas o Java não pode usar porque seu tipo inteiro mais longo é o de 64 bits long. Este é um caso extremo. Sob condições práticas, as considerações de largura de banda de E / S e memória impedem que o código C seja realmente três vezes mais rápido que o Java.

Thomas Pornin
fonte
Hmm ... eu pensei que a maioria das bibliotecas C também estavam dinamicamente ligadas hoje em dia. Ou você está falando de algo diferente?
Sean McMillan
4
@Sean: o vínculo dinâmico para C ocorre para "símbolos externos": as funções usadas em uma DLL e definidas em outra. Um aplicativo C típico usará uma dúzia de DLL. Para Java, a vinculação dinâmica ocorre para todos os métodos em todas as classes: existem milhares deles em um aplicativo Java típico (incluindo a biblioteca padrão). No mundo C, a maioria dos links (todos os links que não ultrapassam um limite de DLL) são resolvidos no tempo de compilação, apenas uma pequena proporção ainda resta em tempo de execução.
Thomas Pornin
14

Java é definitivamente lento, especialmente para trabalho quantitativo.

Eu uso uma combinação de R , Python e C / C ++ com bibliotecas ATLAS multithread otimizadas . Em cada uma dessas linguagens, posso multiplicar por matriz uma matriz de duplas de 3000 por 3000 em cerca de 4 segundos. Usando Colt e Parallel Colt em Java, a mesma operação leva 185 segundos! Surpreendente, apesar dessas bibliotecas java serem paralelas por natureza.

Portanto, o Java puro não é adequado para o trabalho quantitativo. O Jblas parece ser a melhor biblioteca de álgebra linear para Java, pois usa o ATLAS.

Minha máquina é um HP Core 2 Duo com 3 GB de RAM. Eu uso o Ubuntu 10.04 de 64 bits (Lucid Lynx).

Hamaad Shah
fonte
Seguindo meu comentário acima, realizei a mesma operação de multiplicação de matrizes usando JAMA e levou cerca de 50 segundos. Ainda muito lento em comparação com outros idiomas.
Hamaad Shah 26/05/10
7
Quanto tempo o Java levou quando você executou a multiplicação nos libraires chamados via JNI. Dado que qualquer coisa que você possa fazer em C / C ++, você pode fazer com o JNI (adicione algumas centenas de mnano-segundos) a margem é relativamente pequena. Suponho que sua multiplicação de matrizes R e Python não foi escrita em R ou Python, apenas chamada dessas linguagens.
Peter Lawrey
2
Por curiosidade, você fez algum perfil para identificar se você tem algum ponto ativo no seu código (conversão de tipo / caixa automática)?
Thorbjørn Ravn Andersen
10

Para a experiência da maioria das pessoas interagindo com ele - o Java é lento. Todos nós já vimos essa xícara de café girando no nosso navegador antes que algum applet apareça. Demora um pouco para ativar a JVM e fazer o download dos binários do applet, o que afeta a experiência do usuário de uma maneira que é notada.

Não ajuda que o tempo lento de spin-up da JVM e de download de applets seja marcado com uma xícara de café Java, para que as pessoas associem a espera ao Java. Quando o Flash demora muito para carregar, a marca da mensagem "loading" é especificada pelo desenvolvedor do Flash, para que as pessoas não culpem a tecnologia do Flash como um todo.

Tudo isso não tem nada a ver com o desempenho do Java em um servidor ou nas várias outras maneiras pelas quais o Java é usado fora do navegador. Mas é o que as pessoas veem e o que os desenvolvedores que não são Java lembram quando pensam em Java.

Spike Williams
fonte
9

Java tem a reputação de ser lento porque era lento. As primeiras versões do Java tinham uma compilação Just In Time inexistente ou bastante ruim. Isso significava que o código, apesar do bytecode, estava sendo interpretado; portanto, mesmo para as operações mais simples (como a adição de dois números inteiros), a máquina precisava fazer todos os tipos de comparações e dereferências de ponteiros e chamadas de função. O compilador JIT está sempre melhorando; agora é no ponto em que, se eu escrever código C ++ descuidadamente e código Java descuidadamente, o Java às vezes supera o C ++ porque o compilador JIT percebe que eu tenho algumas desreferenciações desnecessárias de ponteiros e cuidará disso para mim.

Se você quiser ver o quão grande a diferença na compilação JIT, confira os benchmarks interpretados versus não interpretados no Computer Languages ​​Benchmark Game . (O Pidigits usa uma biblioteca externa para fazer todos os cálculos, para que o benchmark não mude; os outros mostram uma aceleração de 6-16x!)

Então, essa é a principal razão. Existem várias outras razões menores que não ajudaram: originalmente, o tempo de inicialização do Java era lento (agora corrigido); os aplicativos da web em Java demoram muito tempo para baixar (muito menos verdadeiro agora com banda larga amplamente acessível e com grandes coisas como filmes sendo esperados); o Swing da interface do usuário não foi (e ainda não é) escrito com o desempenho em mente, portanto é muito menos ágil do que os equivalentes, por exemplo, em C ++.

Rex Kerr
fonte
6

Java era lento, antigamente. Tornou-se muito mais rápido, devido a algumas gerações de aprimoramentos de desempenho . A última vez que ouvi falar, geralmente está dentro de 10% da velocidade do C # - às vezes mais rápida, às vezes mais lenta.

A inicialização do applet Java ainda é lenta porque é necessário iniciar uma JVM inteira, que precisa carregar todas as suas classes. Um pouco como inicializar outro computador. Depois que a JVM é iniciada, é bastante rápido, mas geralmente é o que as pessoas lembram da inicialização.

Além disso, existem pelo menos algumas pessoas que nunca acreditarão na viabilidade do Java.

Kaleb Brasee
fonte
1
A inicialização da JVM ainda é muito mais lenta que a inicialização do CLR, infelizmente. Isso ocorre porque Sun tem arrastado seus pés no pior maneira a liberar Java 7, por isso estamos presos com manchas incrementais para a 4 anos de idade Java 6.
BobMcGee
3
Uau, o Java 6 tem 4 anos ??? Sim, acho que sim (se você contar a versão beta). Ainda me parece novo - parei de usar o 1.4 no trabalho.
Kaleb Brasee
O Java 1.4 é utilizável, mas meio sucktastic, já que 1.5 e 1.6 adicionaram muitos aprimoramentos de desempenho e açúcar sintático. As otimizações de verificação de limites e System.arraycopy foram introduzidas desde então. O mesmo aconteceu com muitas melhorias na sincronização. Eu acho que é justo dizer que 1.4 realmente é lento.
precisa saber é o seguinte
LOL, eu sei - toda vez que preciso iterar manualmente ou usar uma matriz em vez de uma lista genérica, quero dividir meu laptop ao meio ... A IBM realmente tem o Java 5 disponível no WAS 6.1 há anos, mas eu ' Fui preso no WAS 6.0 :( Estou usando o Java 5/6 desde que foi lançado para minhas próprias coisas, mas estou limitado apenas pelas versões antigas do servidor em funcionamento. Há melhorias de desempenho de dois dígitos na porcentagem de 1,4 para as versões mais recentes para um monte de coisas, e eu estou ansioso para eles.
Kaleb Brasee
6

Stefano:

Eu estou no Java desde o início, portanto, do meu ponto de vista, a fama de ser lento foi criada por front-ends da GUI não responsivos e lentos (AWT e Swing) e em Applets provavelmente por causa dos tempos de inicialização lentos adicionais do VMs.

O Java estipulou e promoveu muitas pesquisas na área de VM, e houve algumas melhorias, incluindo a coleta de lixo (você pode ajustar muitas coisas, na verdade; no entanto, muitas vezes vejo sistemas nos quais apenas os padrões são usados) e hotspot otimização (que no início e provavelmente ainda é mais eficiente no lado do servidor).

Java no back-end e no nível computacional não é tão lento. Colt é um dos melhores exemplos:

A última versão estável do Colt quebra a barreira de 1,9 Gflop / s no JDK ibm-1.4.1, RedHat 9.0, 2x [email protected] GHz.

Há muitas coisas fora do mainstream do Java que devem ser consideradas, como o Realtime Java ou mecanismos especiais para aumentar a velocidade como o Javolution , bem como a compilação Antecipada (como o gcj). Além disso, existem ICs que podem executar o Java Bytecode diretamente, como, por exemplo, o que está no ARM Jazelle de iPhones e iPods atuais .

Eu acho que geralmente hoje é uma decisão política (como nenhum suporte a Java no iPhone / iPod) e uma decisão contra Java como uma linguagem (porque muitos pensam que é muito detalhado).

No entanto, existem muitas outras linguagens para a Java VM atualmente (por exemplo, Python, Ruby, JavaScript, Groovy, Scala etc.) que podem ser uma alternativa.

Pessoalmente, continuo gostando dela como uma plataforma flexível e confiável, com excelente disponibilidade de ferramentas e bibliotecas, que permite trabalhar com tudo, desde o menor dispositivo (por exemplo, JavaCard) até os maiores servidores.

Dieter
fonte
Ok, então outra má reputação veio do kit de ferramentas da GUI. É claro que presumo que, como a JVM moderna usa widgets nativos, eles se conectam às bibliotecas do sistema operacional, certo? ou eles usam AWT / Swing para renderizar a mesma aparência da plataforma host?
Stefano Borini
Stefano: O swing é na verdade baseado na idéia de renderização universal não-nativa de widgets, então sua suposição está meio errada. Na verdade, é um mecanismo de "aparência e toque conectável" que permite que os componentes Swing imitem a aparência dos componentes nativos. Se você está procurando algo parecido com isso, consulte o SWT ( eclipse.org/swt ), que realmente se conectará ao sistema operacional nativo e usará widgets nativos usando JNI (que é considerado um gargalo).
Dieter
Atualmente, o Java2D (usado para Swing) é muito rápido e o uso de widgets nativos (SWT) não oferece benefícios de desempenho. Pelo menos, foi o que li quando decidi aprender Swing ou SWT há 6 meses.
Luigi Plinge
4

Um martelo é muito mais lento ao estender a massa do que muitas outras ferramentas. Não torna o martelo "mais lento", nem menos útil para as tarefas para as quais foi projetado.

Como uma linguagem de programação geral, Java está a par de muitas (se não a maioria) para uma ampla variedade de tarefas de programação. Existem testes triviais e específicos para os quais o Java não supera as soluções codificadas à mão em linguagens menos sofisticadas, aquelas que estão "mais próximas do metal".

Mas quando se trata de "aplicativos do mundo real", o Java geralmente é a ferramenta certa. Agora, dito isso, nada impedirá os desenvolvedores de criar uma solução de baixo desempenho usando QUALQUER ferramenta. O uso indevido da ferramenta é um problema bem conhecido (veja as reputações do PHP e do VB). No entanto, o design e a sintaxe limpos do Java (principalmente) fazem muito para reduzir o uso indevido.

mobiGeek
fonte
3

Java é uma linguagem de alto nível e sua reputação hoje em dia é ter desempenho igual a outras linguagens de alto nível comparáveis.

  1. Possui semântica de ligação dinâmica . Comparado ao C ++, em que métodos não virtuais são compilados como chamadas de função, até o melhor compilador Java do mundo precisa produzir código menos eficiente. Mas também é uma semântica mais limpa e de alto nível.

  2. Não me lembro dos detalhes, mas ouvi nos primeiros dias de Java que havia um mutex por objeto Java, a ser adquirido e liberado por cada método. Isso tende a torná-lo melhor adaptado à simultaneidade, embora, infelizmente, apenas um mutex por objeto não o proteja de raças, impasses ou qualquer uma das coisas ruins que podem acontecer em programas simultâneos. Essa parte, se verdadeira, é um pouco ingênua, mas veio de boas intenções. Sinta-se à vontade para me informar sobre os detalhes, se você souber mais sobre esse aspecto.

  3. Outra maneira pela qual o Java é uma linguagem de alto nível é através da coleta de lixo . Coleta de lixo pode ser mais lenta do que malloce freepara programas que alocam uma só vez toda a memória de que necessitam e trabalhar com isso. O problema é que, em idiomas que não possuem Garbage-Collection, os programadores tendem a escrever apenas programas que alocam toda a memória necessária de uma só vez e falham se ocorrer alguma transbordamento constante de tamanho máximo arbitrário. Portanto, a comparação é de maçãs com laranjas. Quando os programadores se esforçam para escrever e depurar programas com alocação dinâmica de estruturas encadeadas em linguagens não-GC, às vezes descobrem que seus programas não são mais rápidos do que em uma linguagem GC, porque mallocefreenão são grátis! Eles também têm sobrecarga ... Além disso, não ter um GC forçado a especificar quem libera o quê e ter que especificar quem libera o que, por sua vez, obriga a fazer cópias - quando várias funções precisarão dos dados e não está claro qual o usará por último - enquanto a cópia não seria necessária em um idioma do GC.

Pascal Cuoq
fonte
1. Provavelmente não é verdade com o HotSpot. 2. Somente se você marcar o método como sincronizado.
Winston Ewert
1
1. O compilador não otimiza o código, mas a JVM é inteligente o suficiente para determinar dinamicamente que apenas um ou dois métodos virtuais são normalmente chamados e podem chamá-los de forma estática ou até incorporá-los. Tenho certeza de que o C ++ não pode incorporar métodos virtuais. 2. Todo objeto Java possui um bloqueio. Ele possui uma pequena sobrecarga (aproximadamente um byte) em cada objeto, mas tem pouco impacto se não for usado. 3. Em Java, você pode alocar de uma vez todos os Objetos necessários. Isso pode dar a você uma aplicação que não faz GC o dia todo. ;) O GC do Java é implicitamente multiencadeado, algo que requer bibliotecas especiais em C ++.
Peter Lawrey
O C ++ pode integrar chamadas virtuais, mas o Java pode fazê-lo em mais casos e também é mais forte com a otimização de sites de chamadas megamórficos.
Piotr Kołaczkowski
2

Em meados dos anos 90, quando o Java atingiu o mainstream, o C ++ era a linguagem dominante e a web ainda era relativamente nova. Além disso, JVMs e GC eram conceitos relativamente novos no desenvolvimento convencional. As primeiras JVMs eram um pouco lentas (em comparação com o C ++ rodando em bare metal) e também sofriam de algumas vezes longas pausas na coleta de lixo, o que fazia com que a reputação do Java fosse lenta.

Ken Liu
fonte
isso foi devido à tecnologia por trás do GC? Eu sei que eles têm algumas estratégias (como camadas geracionais para objetos) para serem mais eficientes na fase de GC. Qual era a estratégia naquela época?
Stefano Borini
1
Especialista em JVM da IANA, mas acho que na época havia um único algoritmo de marca / varredura encadeada usado para o GC, que exigia que toda a JVM fizesse uma pausa enquanto o GC estava sendo executado. Atualmente, existem marcas / varreduras simultâneas e também existem muitos outros aprimoramentos de desempenho na JVM.
Ken Liu
2
Os algoritmos modernos de GC são bons, mas acho que a maior melhoria foi o JIT.
Pascal Thivent
1

Muitos aplicativos de desktop Java (atualmente: coisas como Eclipse) têm uma capacidade de resposta da GUI ruim, provavelmente devido ao alto consumo de memória e ao fato de o classloader poder fazer muitas IO. Está melhorando, mas piorou há alguns anos.

Muitas (muitas) pessoas gostam de fazer generalizações e dizem "Java é lento" porque percebem que os aplicativos são lentos quando interagem com eles.

Wojciech Kaczmarek
fonte
você acha que o alto consumo de memória vem da ferramenta ou das bibliotecas java?
Stefano Borini
No caso do Eclipse - da própria infraestrutura do Eclipse. O mesmo para GUIs "pesadas" no passado (JBuilder como eu me lembro). Tenho a sensação de que é porque muitos objetos clichê são necessários para usar uma arquitetura de plug-in (como o Eclipse) em uma linguagem de tipo estaticamente. O Emacs também possui plugins e seu consumo de memória é 10 a 20 vezes menor que o Eclipse ao fazer codificação típica. O código Emacs Lisp é compilado no bytecode e carregado na instância do emacs e depois executado - semelhante ao Java classloader. Eu acho que em Java existem toneladas de objetos intermediários instanciados para permitir alguma plugabilidade.
Wojciech Kaczmarek
1

O principal problema com aplicativos java é que ele é enorme devido ao grande tamanho da biblioteca de tempo de execução de estoque. Programas enormes enchem muito a memória e tendem a trocar, o que significa que ficam lentos.

A razão pela qual a Sun JVM é grande é porque possui um interpretador de código de bytes muito bom, que funciona acompanhando muitas coisas. Isso significa muitos dados, o que significa memória.

Você pode querer olhar para a máquina virtual jamvm, que é um intérprete razoavelmente rápido (sem código nativo) e muito pequeno. Até inicia rápido.

Thorbjørn Ravn Andersen
fonte
1

Como Pascal diz, Java está a par com outras linguagens de alto nível. No entanto, como alguém que trabalhou com as JVMs originais no Windows 98 , na época, o nível de abstração fornecido pela máquina virtual Java era, digamos, doloroso.

Basicamente, era a emulação de software com pouca ou nenhuma otimização que tomamos como certa hoje na JVM.

caskey
fonte
0

As pessoas normalmente traçam a linha "está interpretado". Porque era uma vez, e a má imprensa é transmitida por pessoas que descartaram o Java como "muito lento" e nunca mais voltaram para testar versões mais recentes.

Ou talvez "as pessoas sejam idiotas" seja uma resposta melhor.

Mr. Boy
fonte
0

Acho que algum dia, talvez não em um futuro muito próximo, as linguagens compiladas pelo JIT irão superar as linguagens compiladas em qualquer aspecto (bem, talvez não no tempo de inicialização / consumo de memória) devido ao fato de que os compiladores JIT podem fazer uso pesado do tempo de execução comportamento e a plataforma em que estão rodando.

helpermethod
fonte
6
Eu acho que o que você quer dizer é que o código compilado por JIT (não interpretado) irá superar o código AoT. A interpretação sempre será mais lenta que a execução do código compilado. É por isso que os compiladores JIT são usados. O problema: há pouca diferença entre um compilador antecipado e um compilador JIT em termos de saída, exceto que um compilador JIT deve compilar mais rapidamente e pode usar informações de tempo de execução para sugerir suas otimizações. Os compiladores AoT específicos da plataforma com otimizações específicas da plataforma quase sempre superam o JIT porque não há limite quanto tempo eles gastam na otimização.
BobMcGee
Obrigado pela resposta, nunca pensei no pouco tempo que os compiladores JIT têm à sua disposição.
helpermethod
você quer dizer, algo como otimização adaptativa de hotspot?
Stefano Borini
2
@BobMcGee: Muito bem. Um programa C ++ pode ser criado para ser executado lentamente com feedback do perfil para todas as suas operações. Em seguida, o compilador fica livre para reconstruir uma versão muito rápida usando meia hora de tempo de CPU e 2 GB de RAM. Um JIT que fizesse isso faria com que os usuários saíssem.
Zan Lynx
1
O tempo de compilação JIT é insignificante para aplicativos de longa execução, como servidores. AOT com PGO é mais limitado comparado ao JIT por pelo menos 2 razões. Primeiro, a maior diferença de desempenho é alcançada por otimizações leves. Compare gcc -O2 com gcc -O3. Na maioria das vezes não há diferença , às vezes -O3 pode ser um pouco melhor, às vezes um pouco pior, mas nunca tive uma diferença> 2x disso. Segundo, usando o AOT, mesmo com o PGO, você pode apenas adivinhar qual será o perfil no site de uso. Acho que está errado, e você está muito atrás do JIT. E o perfil real pode ser extremamente dependente da configuração.
Piotr Kołaczkowski