Você deve minimizar a criação de muitos objetos pequenos?

10

Ao escrever algo que cria muitos (1000s) de objetos pequenos com frequência, você deve minimizá-lo para obter desempenho? Especialmente se você não souber em qual sistema ele será executado, de computadores de mesa de ponta a ponta ou até móveis. Para dispositivos móveis, ouvi dizer que a criação de muitos objetos dificulta bastante o desempenho, embora eu não saiba o quanto isso é verdade.

Eu tenho um exemplo que mostra bem essa ideia. Em um programa gráfico, digamos que exista um método usado para todos os desenhos idealmente chamados drawPixel(Point). Pode haver milhares de pontos criados e isso pode ser repetido com frequência, como em um jogo em que poderia ser chamado mais de 60 vezes por segundo. Como alternativa, drawPixel(int x, int y)poderia ser usado para minimizar a criação de muitos objetos Point.

Em um design orientado a objetos, acho que usar o Point seria preferido. No entanto, o uso de tipos primitivos pode aumentar o desempenho. O ganho de desempenho pode ser insignificante na maioria dos casos, mas não tenho certeza sobre coisas como máquinas móveis ou mais antigas. Qual é o ganho de desempenho ao fazer algo assim e é algo que deve ser levado em consideração?

Stripies
fonte
Estou tendo dificuldades para encontrar referências para fazer backup disso, mas em geral no Java 8 simplesmente não se preocupe. Não faça coisas obviamente estúpidas, mas se você não for deliberadamente um desperdício, o sistema deve funcionar muito bem. A Sun / Oracle teve cerca de 20 anos para ajustar o GC e o gerenciamento de memória e ficou muito bom nisso.
@ Snowman Ouvi dizer que as versões mais recentes do Java se saem melhor com o gerenciamento de memória, mas o problema que vejo é que não há garantia de que o usuário não esteja usando uma versão mais antiga. Isso é parte do que criou essa minha preocupação.
Stripies 14/09/16
1
Primeiro, faça algumas medições de desempenho. Se você tiver alguns problemas, pense em como otimizar. Mas não sacrifique a manutenção do código muito cedo, porque você acha que pode ter alguns problemas de desempenho.
Manchou
2
@ Stripies Desempenho de objetos Java de vida curta já respondidos em Devemos evitar a criação de objetos em Java? . No entanto, se você precisar lidar com centenas de milhões de objetos por segundo, somente nesse momento reconsidere esse problema.
rwong 14/09/16
1
Se você estiver preocupado com versões mais antigas do Java, verifique isso ao instalar. Uma JVM com idade suficiente para causar um problema no gerenciamento de memória também possui muitos problemas de segurança conhecidos, portanto, solicitar aos usuários que atualizem está fazendo um favor a eles. System.getProperty("java.version")(ou "java.vm.version") é um ponto de partida.
Jerry Coffin

Respostas:

17

Em geral, não , você não deve evitar criar objetos por medo de perda de desempenho. Há várias razões para isso.

  1. Usar objetos é o tipo de objetivo de usar Java. Evitá-los preventivamente é um sinal de que a decisão de usar Java pode não ter sido a correta.
  2. Problemas de desempenho são notoriamente difíceis de prever. Nunca assuma que algo é um gargalo. Sempre meça. A engenharia de desempenho é quase sempre uma questão de fazer pequenas mudanças exatamente no lugar certo. Você não pode prever o lugar certo sem medir mais do que pode prever o efeito de um medicamento sem um experimento.
  3. O custo da criação do objeto é superestimado. Em uma JVM moderna, isso equivale basicamente ao incremento de um ponteiro (e com coletores de lixo geracionais, o custo de gerenciamento também é trivial). Existem muitos textos na internet que aconselham você a evitar objetos, a usar o pool de objetos etc. Esse aviso às vezes era correto nos anos 90; hoje é principalmente obsoleto. É improvável que você obtenha desempenho suficiente para justificar o custo e a complexidade adicionais de desenvolvimento introduzidos evitando objetos ou gerenciando você mesmo.

Dito isto, há lugares em que transformar algo em um objeto não faz sentido, para começar. Passar duas coordenadas para uma rotina de desenho pode ser o caso: o par de coordenadas não tem existência independente, não tem identidade, é usado apenas uma vez e depois descartado imediatamente, etc.

Se for esse o caso, com certeza, vá em frente e passe dois ints em vez de envolvê-los em um objeto. O ponto de POO não é que tudo deve ser um objeto. A questão é que os objetos facilitam o desenvolvimento em locais onde são a solução natural para um problema de representação de dados. Não evite objetos onde eles fazem sentido - não os apresente onde não fazem.

Kilian Foth
fonte
2

Ao contemplar os impactos no desempenho antes de escrever o código, você deve assumir que não sabe o que está fazendo.

Há uma sobrecarga de espaço muito pequena para objetos em java versus primitivos. Quanto menores os objetos, maior será a porcentagem de sobrecarga. No entanto, aprendi há muito tempo que coisas que dobram n não são nada em comparação com coisas que multiplicam n por n.

Portanto, embora sim, você pode organizar um sistema que tenha metade do tamanho ou até um quarto, por favor, pergunte-se por que realmente se importa. Soluções complicadas para esse problema não serão bem recebidas. Particularmente porque mergulhar nesse código será confuso. Programadores confusos escrevem código incorreto. Eles escrevem n vezes n código que deve ser n log n código. E eles demoram mais para fazer isso.

Agora, se você puder me poupar espaço com algum truque que caiba em uma caixa legal, não preciso olhar para dentro na maior parte do tempo para conversar. Se for uma caixa, eu posso trocar por outra, quando essa caixa funcionar melhor, posso até pagar por ela.

candied_orange
fonte
2

No ajuste de desempenho que fiz ( exemplo ), é muito fácil o gerenciamento de memória ser o principal culpado. Não me importo com o quão loucamente eles ajustaram o novo operador e o coletor de lixo, o cálculo mais rápido é o cálculo. Portanto, se eu descobrir que o gerenciador de memória leva uma boa porcentagem de tempo e não consigo evitar a criação de objetos , encontro uma maneira de reutilizá-los, em vez de criar constantemente novos.

Só o faço se tiver que fazer objetos. Para gráficos, geralmente não. IMHO, os gráficos devem ser desenhados , não construídos . Claro, você poderia dizer que uma imagem consiste em pontos, linhas que os conectam, polígonos, texto e assim por diante. Isso não significa que você não tem alternativa para criar objetos com eles antes de desenhá- los. Eu apenas os desenhei.

Existe um método Paint. Eu substituo isso, desenhe tudo em um bitmap e, em seguida, bloqueio a transferência para a tela. Parece instantâneo. Para entrada do mouse, existem métodos para substituir, detectar clique, arrastar, o que for.

OOP é uma boa ideia por certos motivos. Esses motivos não se aplicam a todas as situações.

Mike Dunlavey
fonte
Eu concordo, mas também concordo com todos que o teste é a única maneira de ter certeza. Certifique-se de ter especificações fazendo isso da maneira simples / óbvia antes de otimizá-lo ... mas concordo que o novo ainda pode ser um problema.
Bill K
2

Vá em frente e use pequenas alocações. Os gerenciadores de memória modernos, particularmente o gerenciador de objetos Java altamente otimizado, são extremamente eficientes. Salve a otimização de desempenho principal para um programa de trabalho.

É extremamente provável que o desempenho geral seja adequado. Se você achar que não é esse o caso, então, e somente então , analise o desempenho do código. Em uma longa carreira de desenvolvimento de software, aprendi que os gargalos quase nunca estão onde você espera.

Certa vez, um membro da equipe passou vários dias tornando a pesquisa de membro do objeto 20x mais rápida. Sucesso! No entanto, a melhor aceleração geral no uso real foi medida em centésimos de um por cento. A alteração foi imediatamente restaurada, pois a aceleração exigia alocações de memória maiores por membro.

Bill Ferguson
fonte
1

É simples: se você precisar de 1000 objetos pequenos, crie 1000 objetos pequenos e não se preocupe. Se você precisar de 100 objetos pequenos, criar 1000 objetos pequenos é estúpido - crie os que você precisa e não mais.

Se você está preocupado com o desempenho (e se também não está preocupado com o desempenho), deve ter qualquer funcionalidade escrita uma vez em um só lugar, o que torna todo o código mais simples e fácil de entender. Então, se você tiver um problema de desempenho, a medição poderá mostrar que existe um local onde o problema ocorre, o que facilita as coisas e apenas um local em que você precisa alterá-lo. Ou a medição mostra que este lugar não causa problemas, então está pronto.

gnasher729
fonte