Devemos evitar a criação de objetos em Java?

243

Foi-me dito por um colega que na criação de objetos Java é a operação mais cara que você pode executar. Portanto, só posso concluir a criação do menor número possível de objetos.

Isso parece derrotar o objetivo da programação orientada a objetos. Se não estamos criando objetos, estamos apenas escrevendo um estilo longo de classe C, para otimização?

Slamice
fonte
39
"A criação de objetos Java é a operação mais cara que você pode executar" . Mente em compartilhar a fonte dessa afirmação?
Songo
92
E - operação mais cara em comparação com o que? Comparado ao cálculo de pi com 900 dígitos ou comparado ao incremento de um int?
jasonk
4
Eles poderiam estar falando sobre uma parte específica dessa criação de objeto específico? Estou pensando em como a Apple usa uma fila para tableViewCells. Talvez o seu colega sugerisse criar alguns objetos e reutilizá-los devido a alguma sobrecarga associada a esses objetos específicos? Apenas tentando descobrir por que eles fariam tal afirmação.
Tyler DeWitt
3
Esta é uma das coisas mais engraçadas que eu já ouvi sobre a programação).
Mert Akcakaya
22
A aritmética também é bastante cara; devemos evitar cálculos, ah, e iniciar uma JVM é muito caro, portanto, não devemos iniciar nenhuma JVM :-).
James Anderson

Respostas:

478

Seu colega não tem idéia do que está falando.

Sua operação mais cara seria ouvi-los . Eles desperdiçaram seu tempo desviando-o de informações desatualizadas há mais de uma década (na data original em que essa resposta foi postada) , além de você ter que gastar algum tempo postando aqui e pesquisando na Internet para a verdade.

Espero que eles estejam apenas regurgitando algo que ouviram ou leram de mais de uma década atrás e não sabem nada melhor. Eu aceitaria qualquer outra coisa que eles dissessem como suspeita, essa deve ser uma falácia bem conhecida de qualquer um que se mantenha atualizado de qualquer maneira.

Tudo é um Objeto (exceto primitives)

Tudo que não sejam primitivos ( int, long, doubleetc) são objetos em Java. Não há como evitar a criação de objetos em Java.

A criação de objetos em Java devido a suas estratégias de alocação de memória é mais rápida que o C ++ na maioria dos casos e, para todos os fins práticos, em comparação com tudo o mais na JVM, pode ser considerada "livre" .

No início dos anos 90, as implementações da JVM na década de 90 tinham um pouco de desempenho na alocação real de objetos. Este não é o caso desde pelo menos 2005.

Se você ajustar -Xmspara suportar toda a memória necessária para que seu aplicativo seja executado corretamente, o GC talvez nunca precise executar e varrer a maior parte do lixo nas implementações modernas do GC, os programas de curta duração talvez nunca tenham o GC.

Ele não tenta maximizar o espaço livre, que é um arenque vermelho de qualquer maneira, maximiza o desempenho do tempo de execução. Se isso significa que o JVM Heap é quase 100% alocado o tempo todo, que assim seja. A memória heap livre da JVM não fornece nada apenas para você ficar sentado ali mesmo.

Há um equívoco de que o GC libere memória de volta para o resto do sistema de uma maneira útil, isso é completamente falso!

O heap da JVM não aumenta e diminui, para que o restante do sistema seja afetado positivamente pela memória livre no heap da JVM . -Xmsaloca TUDO o que é especificado na inicialização e sua heurística é nunca realmente liberar parte dessa memória de volta ao sistema operacional para ser compartilhada com outros processos do sistema operacional até que a instância da JVM saia completamente. -Xms=1GB -Xmx=1GBaloca 1 GB de RAM, independentemente de quantos objetos são realmente criados a qualquer momento. Existem algumas configurações que permitem que as porcentagens da memória heap sejam liberadas, mas para todos os propósitos práticos a JVM nunca é capaz de liberar o suficiente dessa memória para que isso aconteça.portanto, nenhum outro processo pode recuperar essa memória; portanto, o resto do sistema também não se beneficia da liberação da JVM Heap. Uma solicitação de proposta foi "aceita" em 29 de novembro de 2006, mas nada foi feito a respeito. Esse é um comportamento que não é considerado uma preocupação por ninguém de autoridade.

Há um equívoco de que a criação de muitos objetos pequenos e de curta duração faz com que a JVM faça uma pausa por longos períodos de tempo, agora isso também é falso

Os algoritmos atuais do GC são realmente otimizados para criar muitos objetos pequenos de vida curta, que é basicamente a heurística de 99% para objetos Java em todos os programas. Tentativas no pool de objetos realmente fazem com que a JVM tenha um desempenho pior na maioria dos casos.

Os únicos objetos que precisam de pool hoje são objetos que se referem a recursos finitos externos à JVM; Soquetes, arquivos, conexões com o banco de dados, etc., e podem ser reutilizados. Objetos regulares não podem ser agrupados no mesmo sentido que em idiomas que permitem acesso direto aos locais da memória. O cache de objetos é um conceito diferente e pode ou não ser o que algumas pessoas chamam de pooling ingenuamente , os dois conceitos não são a mesma coisa e não devem ser confundidos.

Os algoritmos modernos do GC não têm esse problema porque não se desalocam dentro de um cronograma, se desalocam quando a memória livre é necessária em uma determinada geração. Se o heap for grande o suficiente, não haverá desalocações por tempo suficiente para causar pausas.

Linguagens dinâmicas orientadas a objetos estão superando C mesmo hoje em dia nos testes sensíveis à computação.

Comunidade
fonte
275
+1: "Sua operação mais cara seria ouvi-los ...". Melhor que já ouvi há algum tempo.
Rjnilsson 22/05
21
@DeadMG, mesmo com a sobrecarga cumulativa do GC, o Java pode ser mais rápido que o C ++ (por exemplo, devido à compactação de heap, minimizando as falhas de cache para determinadas estruturas de dados).
SK-logic
13
@ SK-logic: Como o GC não é determinístico, é extremamente difícil, na melhor das hipóteses, provar isso. Quanto a minimizar falhas de cache, é difícil fazer isso quando cada objeto deve ser outro indireto, desperdiçando espaço em cache e aumentando o tempo de execução. No entanto, eu afirmo que, simplesmente usando um alocador apropriado em C ++, como pool de objetos ou arena de memória, você pode facilmente corresponder ou superar o desempenho do coletor de lixo. Por exemplo, você pode escrever uma classe de arena de memória com desempenho mais rápido do que _allocaamortizado.
DeadMG
33
A criação de objetos está mais barata agora do que costumava ser. Não é grátis. Quem lhe disser que está mentindo. E o link sobre as línguas OO que batem em C é uma resposta exagerada a alguém que está realmente tentando aprender.
jasonk
17
É por causa desse tipo de resposta que acabamos com códigos ruins. A resposta certa é criar um objeto em Java: criar o objeto Java e inicializá-lo. A primeira parte é barata, a segunda pode ser muito cara. As pessoas devem sempre observar o que acontece nos construtores antes de usar a newpalavra - chave em um local de ponto de acesso. Eu já vi pessoas usarem new ImageIcon(Image)o paint()método de objetos Swing, o que é bastante caro e estava tornando a interface do usuário inteira muito lenta. Portanto, não é uma resposta em preto e branco, pense antes de usar em newalgum lugar.
qwertzguy
94

Conclusão: não comprometa seu design para criar atalhos na criação de objetos. Evite criar objetos desnecessariamente. Se sensato, projete para evitar operações redundantes (de qualquer tipo).

Ao contrário da maioria das respostas - sim, a alocação de objetos TEM um custo associado. É um custo baixo, mas você deve evitar criar objetos desnecessários. O mesmo que você deve evitar qualquer coisa desnecessária no seu código. Gráficos de objetos grandes tornam o GC mais lento, implicando em tempos de execução mais longos, pois você provavelmente terá mais chamadas de método, acionará mais falhas de cache da CPU e aumentará a probabilidade de seu processo ser trocado para o disco em casos de pouca RAM.

Antes que alguém se queixa de que esse é um caso de extrema importância, criei um perfil de aplicativos que, antes de otimizar, criavam mais de 20 MB de objetos para processar ~ 50 linhas de dados. Isso é bom no teste, até você escalar até cem solicitações por minuto e de repente criar 2 GB de dados por minuto. Se você quiser fazer 20 reqs / s, crie 400 MB de objetos e jogue-os fora. 20 reqs / s é pequeno para um servidor decente.

jasonk
fonte
7
Posso acrescentar um exemplo: Em alguns casos, isso realmente não faz diferença em termos de clareza de código, mas pode fazer uma diferença mais ou menos grande no desempenho: Ao ler a partir de fluxos, por exemplo, não é incomum usar algo como o while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...que pode ser um desperdício em comparação com, por exemplo byte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ....
22712 JimmyB
4
+1: a criação desnecessária de objetos (ou melhor, a limpeza após a remoção) pode, por vezes, custar caro. O código 3D Graphics / OpenGL em java é um lugar em que eu vi otimizações feitas para minimizar o número de objetos criados, pois o GC pode causar estragos na taxa de quadros.
Leo
1
Uau! Mais de 20 MB para processar 50 linhas de dados? Parece loucura. De qualquer forma, esses objetos têm vida longa? Porque esse é o caso que importaria para a GC. Se, por outro lado, você está apenas a discutir os requisitos de memória , que é relacionado à coleta de lixo ou a eficiência criação do objeto ...
Andres F.
1
Os objetos têm vida curta (menos de 0,5 s no caso geral). Esse volume de lixo ainda afeta o desempenho.
Jasonk
2
Obrigado por permanecer firme na realidade, qualquer pessoa que viva com os efeitos de uma arquitetura impensada pode se relacionar muito.
JM Becker
60

Na verdade, devido às estratégias de gerenciamento de memória que a linguagem Java (ou qualquer outra linguagem gerenciada) possibilita, a criação de objetos é pouco mais do que incrementar um ponteiro em um bloco de memória chamado geração jovem. É muito mais rápido que C, onde é necessário fazer uma busca por memória livre.

A outra parte do custo é a destruição de objetos, mas é difícil comparar com C. O custo de uma coleção é baseado na quantidade de objetos salvos a longo prazo, mas a frequência das coleções é baseada na quantidade de objetos criados ... em no final, ainda é muito mais rápido que o gerenciamento de memória no estilo C.

amara
fonte
7
+1 Mesmo que o coletor de lixo "simplesmente funcione", todo programador Java deve aprender sobre o coletor de lixo geracional.
benzado
18
As versões mais recentes do Java podem fazer análise de escape, o que significa que ele pode alocar memória para objetos que não escapam de um método na pilha, para que a limpeza seja livre - o coletor de lixo não precisa lidar com esses objetos , eles são descartados automaticamente quando o quadro de pilha do método é desenrolado (quando o método retorna).
Jesper
4
Um próximo passo para a análise de escape é "alocar" a memória para objetos pequenos apenas em registros (por exemplo, um Pointobjeto pode caber em 2 registros de uso geral).
Joachim Sauer
6
@Joachim Sauer: Isso é o que é feito nas implementações mais recentes da VM HotSpot. É chamado de substituição escalar.
Someguy 24/05
1
@someguy: Eu li sobre isso há algum tempo atrás como a próxima coisa, mas não fiz o acompanhamento para verificar se já está pronto. É uma excelente notícia saber que já temos isso.
Joachim Sauer
38

Outros pôsteres apontaram corretamente que a criação de objetos é extremamente rápida em Java e que você não deve se preocupar com isso em nenhum aplicativo Java normal.

Existem algumas situações muito especiais em que é uma boa ideia evitar a criação de objetos.

  • Quando você está escrevendo um aplicativo sensível à latência e deseja evitar pausas no GC. Quanto mais objetos você produz, mais GC acontece e maior a chance de pausas. Essa pode ser uma consideração válida para relevante para jogos, alguns aplicativos de mídia, controle robótico, negociação de alta frequência etc. A solução é pré-alocar todos os objetos / matrizes que você precisa com antecedência e reutilizá-los. Existem bibliotecas especializadas em fornecer esse tipo de capacidade, por exemplo, Javolution . Mas, sem dúvida, se você realmente se importa com baixa latência, deve usar C / C ++ / assembler em vez de Java ou C # :-)
  • Evitar primitivas in a box (Duplo, Inteiro etc.) pode ser uma micro-otimização muito benéfica em determinadas circunstâncias. Como as primitivas sem caixa (double, int etc.) evitam a sobrecarga por objeto, elas são um trabalho muito mais rápido da CPU, como processamento numérico etc. Normalmente, as matrizes primitivas têm um desempenho muito bom em Java, então você deseja usá-las para o processamento de números em vez de quaisquer outros tipos de objetos.
  • Em situações de memória restrita, você deseja minimizar o número de objetos (ativos) criados, pois cada objeto carrega uma pequena sobrecarga (geralmente de 8 a 16 bytes, dependendo da implementação da JVM). Em tais circunstâncias, você deve preferir um pequeno número de objetos grandes ou matrizes para armazenar seus dados, em vez de um grande número de objetos pequenos.
Mikera
fonte
3
Vale ressaltar que a análise de escape permitirá que objetos de vida curta (vida limitada) sejam armazenados na pilha, esses objetos podem ser desalocados gratuitamente ibm.com/developerworks/java/library/j-jtp09275/index.html
Richard Tingle
1
@ Richard: ótimo ponto - análise de escape fornece algumas otimizações muito boas. Porém, você precisa ter cuidado: não é garantido que isso aconteça em todas as implementações Java e em todas as circunstâncias. Então, muitas vezes você precisa fazer benchmark para ter certeza.
Mikera #
2
Além disso, a análise de escape 100% correta é equivalente ao problema de parada. Não confie na análise de escape em situações complexas, pois é provável que dê a resposta errada pelo menos uma parte do tempo.
Jules
O primeiro e o último ponto não se aplicam a objetos pequenos que são liberados rapidamente, eles morrem no éden (pense na alocação de pilha em C, praticamente livre) e nunca afetam os tempos do GC ou a alocação de memória. A maioria da alocação de objetos em Java se enquadra nessa categoria e, portanto, é essencialmente gratuita. O segundo ponto ainda é válido.
Bill K
17

Há um núcleo de verdade no que seu colega está dizendo. Eu respeitosamente sugiro que o problema com a criação de objetos seja realmente a coleta de lixo . Em C ++, o programador pode controlar com precisão como a memória é desalocada. O programa pode acumular petróleo pelo tempo que desejar. Além disso, o programa C ++ pode descartar o crud usando um thread diferente daquele que o criou. Portanto, o encadeamento atualmente funcionando nunca precisa parar para limpar.

Por outro lado, a Java Virtual Machine (JVM) periodicamente interrompe seu código para recuperar a memória não utilizada. A maioria dos desenvolvedores de Java nunca percebe essa pausa, pois geralmente é pouco frequente e muito curta. Quanto mais bruto você acumular ou mais restrita sua JVM, mais frequentes serão essas pausas. Você pode usar ferramentas como o VisualVM para visualizar esse processo.

Nas versões recentes do Java, o algoritmo de coleta de lixo (GC) pode ser ajustado . Como regra geral, quanto menor você desejar fazer as pausas, mais cara será a sobrecarga na máquina virtual (ou seja, CPU e memória gastas coordenando o processo do GC).

Quando isso pode importar? Sempre que você se preocupa com taxas de resposta consistentes em menos de milissegundos, se preocupa com o GC. Os sistemas de negociação automatizados escritos em Java ajustam fortemente a JVM para minimizar as pausas. As empresas que de outra forma gravariam Java recorrem ao C ++ em situações em que os sistemas precisam ser altamente responsivos o tempo todo.

Para o registro, eu não tolero a evitação de objetos em geral! Padrão para programação orientada a objetos. Ajuste essa abordagem somente se o GC estiver no seu caminho e somente depois de tentar ajustar a JVM para pausar por menos tempo. Um bom livro sobre ajuste de desempenho Java é o Java Performance, de Charlie Hunt e Binu John.

greg
fonte
10
A maioria das JVM modernas suporta melhores algoritmos de coleta de lixo do que "para o mundo". O tempo amortizado gasto na coleta de lixo é freqüentemente menor do que o gasto explicitamente chamando malloc / free. O gerenciamento de memória C ++ também é executado em um thread separado?
10
As versões Java mais recentes da Oracle podem fazer uma análise de escape, o que significa que os objetos que não escapam de um método são alocados na pilha, o que os torna livres - eles são desalocados automaticamente quando o método retorna.
Jesper
2
@ ThorbjørnRavnAndersen: Sério? Você realmente quer dizer GC sem pausa , ou quer dizer "normalmente paralelo-mas-às vezes-um-pequeno-bit-pausando" GC? Eu não entendo como o GC nunca pode pausar um programa, e ainda mover objetos ao mesmo tempo ... parece, literalmente, impossível para mim ...
Mehrdad
2
@ ThorbjørnRavnAndersen: Como pode "parar o mundo", mas nunca "pausar a JVM"? Isso não faz sentido ...
Mehrdad 23/05
2
@ ThorbjørnRavnAndersen: Não, eu realmente não; Só não entendo o que você está dizendo. Às vezes, o GC pausa o programa; nesse caso, por definição, não é " sem pausa " ou nunca pausa o programa (portanto, é " sem pausa"); nesse caso, não entendo como isso corresponde à sua declaração "ele para o mundo quando não pode acompanhar", pois isso parece implicar que o programa está em pausa enquanto o GC está em operação. Você se importaria de explicar qual é o caso (é sem pausas ou não?) E como isso é possível?
Mehrdad 23/05
11

Há um caso em que você pode ser desencorajado de criar muitos objetos em Java devido à sobrecarga - projetando para o desempenho na plataforma Android

Fora isso, as respostas acima são verdadeiras.

Peter Kelly
fonte
2
Leia a pergunta novamente. Ele não especifica a JVM em nenhum lugar, incluindo as tags. Menciona apenas Java.
22612 Peter Kelly
9

o GC é ajustado para muitos objetos de vida curta

Dito isto, se você pode reduzir trivialmente a alocação de objetos, deve

Um exemplo seria construir uma string em um loop, a maneira ingênua seria

String str = "";
while(someCondition){
    //...
    str+= appendingString;
}

que cria um novo Stringobjeto em cada +=operação (mais um StringBuildere o novo conjunto de caracteres subjacente)

você pode reescrever isso facilmente em:

StringBuilder strB = new StringBuilder();
while(someCondition){
    //...
    strB.append(appendingString);
}
String str = strB.toString();

esse padrão (resultado imutável e um valor intermediário local mutável) também pode ser aplicado a outras coisas

mas fora isso, você deve criar um perfilador para encontrar o gargalo real em vez de perseguir fantasmas

catraca arrepiante
fonte
a maior vantagem desta StringBuilderabordagem é a pré-size o StringBuildermodo que ele nunca tem que realocar a matriz subjacente com o StringBuilder(int)construtor. Isso o torna uma alocação única , em vez de 1+Nalocações.
2
@JarrodRoberson StringBuilder irá, pelo menos, o dobro da capacidade de corrente ou, por outras palavras, a capacidade vai crescer exponencialmente por apenas log (n) alocações
catraca aberração
6

Joshua Bloch (um dos criadores da plataforma Java) escreveu em seu livro Effective Java in 2001:

Evitar a criação de objetos mantendo seu próprio pool de objetos é uma má idéia, a menos que os objetos no pool sejam extremamente pesados. Um exemplo prototípico de um objeto que justifica um pool de objetos é uma conexão com o banco de dados. O custo de estabelecer a conexão é suficientemente alto para fazer sentido reutilizar esses objetos. De um modo geral, no entanto, a manutenção de seus próprios pools de objetos atrapalha seu código, aumenta o espaço ocupado pela memória e prejudica o desempenho. As implementações modernas da JVM têm coletores de lixo altamente otimizados que superam facilmente esses conjuntos de objetos em objetos leves.

Anthony Ananich
fonte
1
Mesmo com coisas como conexão de rede, o importante não é manter os objetos alocados pelo GC associados às conexões, mas manter o conjunto de conexões que existem fora do mundo gerenciado pelo GC. Há momentos em que o próprio agrupamento de objetos pode ser útil; a maioria delas decorre de casos em que um par de referências ao mesmo objeto pode ser semanticamente equivalente a um par de referências a objetos idênticos, mas distintos, mas, no entanto, têm algumas vantagens. Por exemplo, duas referências à mesma cadeia de cinquenta mil caracteres podem ser verificadas quanto à igualdade ...
supercat
2
... muito mais rápido que as referências a duas seqüências distintas, mas idênticas, desse comprimento.
Supercat 29/12
5

Isso realmente depende da aplicação específica, por isso é realmente difícil de dizer em geral. No entanto, eu ficaria surpreso se a criação de objetos fosse realmente um gargalo de desempenho em um aplicativo. Mesmo que sejam lentos, o benefício no estilo do código provavelmente superará o desempenho (a menos que seja realmente perceptível para o usuário)

De qualquer forma, você não deve nem se preocupar com essas coisas até criar um perfil de seu código para determinar os gargalos de desempenho reais em vez de adivinhar. Até lá, você deve fazer o que for melhor para a legibilidade do código, não o desempenho.

Oleksi
fonte
Nas versões anteriores do Java, havia um custo substancial quando o coletor de lixo limpava objetos descartados. As versões recentes do Java aprimoraram bastante as opções de GC; portanto, a criação de objetos raramente é um problema. Geralmente, os sistemas da web são limitados por chamadas de entrada / saída para sistemas externos, a menos que você esteja computando algo realmente complexo no servidor de aplicativos como parte do carregamento da página.
greg
3

Eu acho que seu colega deve ter dito da perspectiva da criação desnecessária de objetos. Quero dizer, se você estiver criando o mesmo objeto com frequência, é melhor compartilhar esse objeto. Mesmo nos casos em que a criação de objetos é complexa e ocupa mais memória, convém clonar esse objeto e evitar a criação desse processo complexo de criação de objetos (mas isso depende de seus requisitos). Eu acho que a afirmação "A criação de objetos é cara" deve ser tomada em contexto.

No que diz respeito aos requisitos de memória da JVM, aguarde o Java 8, você nem precisa especificar -Xmx, as configurações de metaespaço cuidarão da necessidade de memória da JVM e ela crescerá automaticamente.

AKS
fonte
Seria muito construtivo se as pessoas também comentassem enquanto votavam em alguma resposta. Afinal, estamos todos aqui para compartilhar conhecimento, e simplesmente julgar sem uma razão adequada não vai servir a nenhum propósito.
AKS
1
A troca de pilhas deve ter algum mecanismo para notificar os usuários que recusam qualquer resposta, quando um comentário é publicado sobre essa resposta.
AKS
1

Há mais para criar uma classe do que alocar memória. Também há inicialização, não sei por que essa parte não é coberta por todas as respostas. As classes normais contêm algumas variáveis ​​e fazem alguma forma de inicialização, e isso não é gratuito. Dependendo da classe, ela pode ler arquivos ou executar qualquer outro número de operações lentas.

Portanto, considere o que o construtor da classe faz, antes de descobrir se é gratuito ou não.

Alex
fonte
2
Uma classe bem projetada não deve fazer trabalho pesado em seu construtor, apenas por esse motivo. Por exemplo, sua classe de leitura de arquivos pode reduzir seu custo de instanciação verificando apenas se o arquivo de destino existe na inicialização e adiando qualquer operação real de arquivo até a primeira chamada de método que precise de dados do arquivo.
GordonM
2
Se o custo adicional for movido para 'if (firstTime)', recriar a classe em um loop ainda será mais caro do que reutilizá-la.
24412 Alex
Eu estava prestes a postar uma resposta semelhante e acredito que esta é a resposta certa. Tantas pessoas ficam cegas por dizerem que a criação de objetos Java é barata que não percebem que frequentemente construtores ou inicialização adicional podem estar longe de ser baratos. Por exemplo, a classe ImageIcon no Swing, mesmo se você passar um objeto Image pré-carregado, o construtor é muito caro. E eu discordo do @GordonM, muitas classes do JDK executam a maior parte do init no construtor, e acho que isso torna o código mais enxuto, melhor projetado.
qwertzguy
1

O GC de Java é realmente muito otimizado em termos de criação de muitos objetos rapidamente, de maneira "rápida". Pelo que entendi, eles usam um alocador seqüencial (alocador O (1) mais rápido e mais simples para solicitações de tamanho variável) para esse tipo de "ciclo de burst" em um espaço de memória que eles chamam de "espaço Eden", e somente se os objetos persistirem depois de um ciclo de GC, eles são movidos para um local onde o GC pode coletá-los um a um.

Com isso dito, se o seu desempenho precisa ser crítico o suficiente (como medido com requisitos reais do usuário final), os objetos carregam uma sobrecarga, mas eu não pensaria muito nisso em termos de criação / alocação. Tem mais a ver com a localidade de referência e o tamanho adicional de todos os objetos em Java, conforme necessário para suportar conceitos como reflexão e envio dinâmico ( Floaté maior que float, geralmente algo 4 vezes maior em 64 bits com seus requisitos de alinhamento e um matriz de Floatnão é necessariamente garantida para ser armazenada contígua do que eu entendo).

Uma das coisas mais atraentes que já vi desenvolvidas em Java que me fizeram considerá-lo um contendor pesado no meu campo (VFX) foi um rastreador de caminho padrão interativo e multithread (sem usar cache de irradiância ou BDPT ou MLS ou qualquer outra coisa) em a CPU fornece visualizações em tempo real que convergiram rapidamente para uma imagem sem ruído. Eu trabalhei com profissionais em C ++ dedicando suas carreiras a essas coisas com criadores de perfil sofisticados em mãos que tiveram dificuldade em fazer isso.

Mas espiei o código-fonte e, embora ele usasse muitos objetos a um custo trivial, as partes mais críticas do traçador de caminhos (BVH e triângulos e materiais) evitavam objetos de maneira muito clara e deliberada em favor de grandes matrizes de tipos primitivos ( principalmente float[]e int[]), o que o fez usar muito menos memória e localidade espacial garantida para passar de um floatna matriz para o próximo. Eu não acho muito especulativo pensar que, se o autor usasse tipos de caixas comoFloatlá, teria um custo bastante alto para seu desempenho. Mas estamos falando da parte mais absolutamente crítica desse mecanismo, e tenho certeza, considerando a habilidade com que o desenvolvedor o otimizou, que ele mediu isso e aplicou essa otimização de maneira muito criteriosa, pois ele usava objetos em qualquer lugar com custo trivial para o seu impressionante rastreador em tempo real.

Foi-me dito por um colega que na criação de objetos Java é a operação mais cara que você pode executar. Portanto, só posso concluir a criação do menor número possível de objetos.

Mesmo em um campo tão crítico quanto o meu, você não escreverá produtos eficientes se forçar em locais que não importam. Eu diria até que os campos mais críticos para o desempenho podem exigir ainda mais a produtividade, já que precisamos de todo o tempo extra possível para ajustar os pontos críticos que realmente importam, sem desperdiçar tanto tempo com coisas que não o fazem. . Como no exemplo do traçador de caminhos acima, o autor habilmente e judiciosamente aplicou essas otimizações apenas aos lugares que realmente, realmente importavam, e provavelmente em retrospectiva após a medição, e ainda usavam objetos em qualquer lugar.

Dragon Energy
fonte
1
Seu primeiro parágrafo está no caminho certo. Os espaços eden e young são usados ​​para colecionadores que têm aprox. 0 custo para objetos mortos. Eu recomendo esta apresentação . Em uma nota lateral, você percebe que esta pergunta é de 2012, certo?
JimmyJames
@JimmyJames Fico entediado e gosto de examinar as perguntas, incluindo as antigas. Espero que as pessoas não se importem com a minha necromancia! :-D
Dragon Energy
@JimmyJames Já não é o caso de os tipos de caixa terem requisitos adicionais de memória e não serem contíguos em uma matriz? Costumo pensar que os objetos são muito baratos em Java, mas o único caso em que eles podem ser relativamente caros é como float[]vs. Float[], em que o processamento de um milhão do primeiro sequencialmente pode ser relativamente mais rápido que o segundo.
Dragon Energy
1
Quando comecei a postar aqui, fiz o mesmo. Só não se surpreenda quando respostas a perguntas antigas tendem a receber muito pouca atenção.
precisa saber é o seguinte
1
Tenho certeza de que os tipos de caixa devem assumir mais espaço do que os primitivos. Existem potencialmente otimizações em torno disso, mas eu, em geral, acho que é como você descreve. Gil Tene (da apresentação acima) tem outra palestra sobre uma proposta para adicionar um tipo especial de coleção que forneceria alguns dos benefícios de estruturas, mas ainda usando objetos. É uma ideia interessante, não tenho certeza do status do JSR. O custo é em grande parte devido ao tempo, ao qual você alude. Se você puder evitar que seus objetos 'escapem', eles podem até ser alocados por pilha e nunca tocar na pilha.
precisa saber é o seguinte
0

Como as pessoas disseram, a criação de objetos não é um grande custo em Java (mas aposto que é maior que a maioria das operações simples, como adicionar etc) e você não deve evitá-lo demais.

Dito isso, ainda é um custo e, às vezes, você pode se livrar do maior número possível de objetos. Mas somente após a criação de perfil mostrou que isso é um problema.

Aqui está uma ótima apresentação sobre o tema: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf

rkj
fonte
0

Eu fiz uma rápida marca de microbench sobre isso e forneci fontes completas no github. Minha conclusão é que se a criação de objetos é cara ou não, não é o problema, mas a criação contínua de objetos com a noção de que o GC cuidará de tudo, pois você fará com que seu aplicativo inicie o processo do GC mais cedo. O GC é um processo muito caro e é melhor evitá-lo sempre que possível e não tentar pressioná-lo.

Archimedes Trajano
fonte
isso não parece oferecer nada substancial sobre os pontos apresentados e explicados nas 15 respostas anteriores. Dificilmente um conteúdo vale a pena bater uma pergunta que foi feita mais de 2 anos e tem obtido um resposta muito completa
mosquito