Otmização de objetos Java

Olá, pessoal do GUJ.

Não consegui decidir qual seria a área do fórum caberia esse tópico. Mesmo assim, aí vai minha dúvida:

Gostaria de saber se existe no Java alguma abordagem para trabalhar classes que vão ser criadas e destruídas o tempo todo, por exemplo, classes que representassem pontos na tela. Existe alguma maneira de criar objetos que sejam mais rápidos e consumam menos memória, ou não preciso me preocupar com isso?

Grato pela compreensão.

Eu mesmo acho que achei uma resposta. Basta usar a palavra chave final:

public final class Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

Alguém tem um comentário sobre isso?

Ué… não bastaria vc instanciar um objeto e quando não for mais usá-lo dar um null nele?!

nao tenho certeza mais acho que o final é mais adequado.

O uso da palavra final só quer dizer que essa classe não poderá ser herdada, mas em questão a tamanho de memória influi? Nunca li nada sobre isso!

boa pergunta, tambem não sei responder!

Olá,

A palavra-chave final pode ter algumas implicações de performance - é um assunto que eu não conheço muito bem, mas trata-se do compilador JIT. Porém, imagino que o ganho não vai ser muito dramatico.

Você vai ter quantos objetos? 100 pontos? Um objeto para cada ponto de uma tela de 1024x768 (786432 objetos)? 786432 objetos novos 24 vezes por segundo?

Dependendo do que você está querendo fazer, daria pra usar o padrão Flyweight, ou simplesmente usar um array de tipos primitivos.

[]s,
Sami

Isso mesmo Sami
a melhor maneira de fazer isso eh não criar os objetos o tempo todo
apenas 2 vezes no seu caso…
usando o primeiro conjunto como buffer (zona de trabalho)
e o segundo como zona de exibição ();

vc faz oque tem que fazer na zona de trabalho

e quando acabar (1/24 por segundo…sei la…o teu fps ai)

copia tudo pra zona de exibição…

trabalhando desse jeito vc consegue até separar em Threads a sua implementação
usando uma pra logica e outra apenas pra redesenho…

mais ficar criando objetos o tempo todo não eh legal, e nunca vai ficar rapido…
quer dizer…quem sabe no core256Duo… :stuck_out_tongue:

Muito obrigado pelas respostas, pessoal.

É justamente esse meu problema. Pretendo criar um software que desenhe objetos, pontos e figuras geométricas na tela. O problema é que não sei, a princípio, quantos objetos o usuário vai criar.

Devo então criar um objeto para cada ponto? Um objeto novo para cada figura geométrica desenhada?

E o que seria o padrão Flyweigh?

Ok, inicialmente eu diria que uma quantidade de objetos que o usuário cria manualmente acho que não vai causar grandes problemas em termos de memória. O que é mais problematico (mas talvez também nem seja um problema) é o desempenho de desenhar e redesenhar esse objetos, pontos e figuras geométricas. Se o usuário pode mover uma das suas figuras, ou um ponto da figura, você terá que limpar a tela e redesenhar todos os objetos.

O Flyweight é uma padrão onde você reutiliza objetos imutáveis, mas agora que você explicou seu cenário, não acho mais útil no seu caso.

Na minha opinião, sim.

[]s,
Sami

Pois é cara…tava pensando que tu queria fazer
um Sand da vida…aqueles programas de fisica e fluidos bem legais :stuck_out_tongue:
Eu tenho um paint aqui meu, e minha implementação ficou bem rapida,
mesmo com varios objetos em cena.

Use o JComponent como base para seus objetos de desenho
e tb para o seu local de desenho.

porque?

bem, porque o swing tem um ótimo sistema de desenho
e suporte a transparencia (setOpaque(false)).
alem de possuir hierarquia de objetos…todo JComponent é um Container
vc pode adicionar um dentro do outro e criar niveis…igual as camadas do photoshop

dica: sobreescreva apenas o paintComponent()

Entendi…

Muito obrigado pelas dicas. Elas serão muito úteis.

Mais uma coisa. Através do paintComponent() é possível personalizar também a aparência dos componentes?

Claro que sim, ai vc tem 2 maneiras de fazer isso

  1. chamando antes de qualquer coisa o super.paintComponent() e depois desenhando “por cima” da pintura original.

  2. não chamando o super.paintComponent() nunca, ai o desenho todo fica por sua conta.

métodos uteis : getVisibleRect() = area aonde o componente esta para desenhar :slight_smile:

Mais já aviso, o jeito correto de mudar a aparencia dos componentes é extendendo uma classe de ComponentUI
da vida… isso para componentes que o usuario vai usar no programa, já para seus objetos de desenho pode sobreescrever mesmo o paintComponent() somente.

:wink:

[quote=MNeto]Olá, pessoal do GUJ.

Não consegui decidir qual seria a área do fórum caberia esse tópico. Mesmo assim, aí vai minha dúvida:

Gostaria de saber se existe no Java alguma abordagem para trabalhar classes que vão ser criadas e destruídas o tempo todo, por exemplo, classes que representassem pontos na tela. Existe alguma maneira de criar objetos que sejam mais rápidos e consumam menos memória, ou não preciso me preocupar com isso?

[/quote]

Numa primeira abordagem vc não deve se preocupar com isso.
Objetos ocupam a memoria que acupam. não importa qual, será sempre a mesma.

Numa segunda abordagem vc deve pensar qual é o tipo minimo que da conta do recado.
Um ponto na tela.será que preciso de um double ? ou um bigDecimal, ou um array ?
Não será que dois short serve ?

Numa terceira abordagem vc tem que pensar que não é a memória que é lenta, é a leitura e escrita dela.
A criação e destruição do objeto são mais relevantes que o objeto em si.
Se for possivel reaproveitar o objeto e apenas modificar o estado,faça-o. Mas normalmente para objetos de valor
como Pontos, isso não é possivel. Neste nivel tem que pensar no tipo de objeto que está usando.

Em caso de duvida não se preocupe com isso.

Muito obrigado pela dica.

A questão mesmo é descobrir a melhor forma de implementar as classes.

Testarei várias possibilidades e analisar o comportamento para ver o que acontece.

Bom, vamos esclarecer alguns mals entendidos. Colocar final pode ter algum impacto em performance, mas ele geralmente é irrisório. Na verdade, há muito mito sobre o final, assim como há mitos também sobre a palavra const, do C++. Veja o artigo do próprio Brian Goetz sobre isso:


O padrão flyweight não se aplica a esse caso. Ele só é aplicado quando você tem um grupo de objetos que podem compartilhar uma característica imutável e pesada. Um exemplo. Suponha que você está fazendo um jogo de “space invaders”. Nesse jogo, há várias naves idênticas. Carregar várias cópias da imagem da nave seria um despedício de tempo e memória. Usa-se então o padrão flyweigth para que as naves compartilhem essa imavel (imutável e pesada), separando isso da parte mutável (posição da imagem na tela).

Antes de falar em otimização, verifique que você tem um problema de performance. Não otimize se não tiver. Estamos falando em quantos pontos? 1, 10, 1000, 1.000.000?

Criar e destruir objetos de mesma estrutura (como os pontos) é uma tarefa muito barata em Java. Isso porque o heap do java irá manter a memória alocada e o custo de pedir e devolver esse dado para o SO, que incomoda tanto os programadores do C++, é muito pequeno aqui. É claro que haverá um pequeno tempo de “warmup”, mas duvido muito que ele será perceptível. Para mais informações: http://www.ibm.com/developerworks/library/j-jtp01274.html

Se tiver um problema, rode um profiler para identificar onde. A maior parte dos gargalos pode ser resolvida com otimizações simples, sem envolver mandraquismos. Um ótimo profiler é o do Netbeans: http://profiler.netbeans.org/docs/help/index.html

Se você mexer no código e não resolver, desfaça a modificação. Dê sempre preferência a um código claro, no lugar de um otimizado. Portanto, se não for absolutamente necessário, não otimize. Se você não estiver fazendo nada animado, provavelmente só usar o swing com cautela te resolverá o problema, e dificilmente você terá que se preocupar com criação/destruição de objetos ou técnicas de otimização.

O swing é legal e rápido, utiliza por padrão double buffering, evita flickering, etc. Mas, para um número grande de pontos em movimento, usar o paintComponent não vai ajudar muito. Você precisará ter mais controle sobre o ciclo de pintura. O swing não garante que a tela será repintada toda vez que o repaint é dado, pois uma técnica chamada event coalescing. Para aplicações de janela, essa técnica evita que muito processamento seja feito desnecessariamente, já que componentes não mudam o tempo todo. Para um efeito de vídeo, ela incomoda.

Então, o que se faz é desabilitar totalmente esse ciclo e usar uma técnica chamada direct painting. Esse tutorial explica como fazer isso:
http://www.cokeandcode.com/info/tut2d.html

Entretanto, se você não está fazendo vídeo, pontos em movimento, como o colega falou, dificilmente você sequer chegará a esse ponto.

Por outro lado… se isso ainda não bastar, você ainda pode ativar o modo full screen exclusivo (FSEM). Ele permite que você desabilite boa parte do ciclo de pintura do Swing, e parta direto para escrita no SO. E ainda deixa sua aplicação em full screen mesmo. Veja sobre isso nesses tutoriais:
http://java.sun.com/docs/books/tutorial/extra/fullscreen/exclusivemode.html
http://fivedots.coe.psu.ac.th/~ad/jg/ch03/index.html

Por fim, se sua aplicação vai gerar uma quantidade absurdamente grande de pontos, recomendo que você parta para um pipeline gráfico que use diretamente a placa de vídeo. Um exemplo disso é desenhar os pontos usando OpenGL. Você pode fazer isso através da JOGL:
https://jogl.dev.java.net/

Há muito material sobre opengl no meu blog, que pode ser facilmente adaptado para java. A vantagem é que aqui a aceleração de hardware será realmente percebida, principalmente se você tiver uma placa de vídeo. É possível renderizar mais de 1 milhão de triângulos em 10 FPS com uma antiga GeForce 4400MX (numa aplicação devidamente otimizada, lógico)…

Se ainda faltar velocidade, algumas técnicas podem otimizar ainda mais:

  1. Use pequenos triângulos com textura no lugar de pontos. Use somente luz ambiente;
  2. Use VertexBuffers ao invés dos métodos mastigados do OpenGL;
  3. Procure desenhar pontos próximos e de mesma característica ao mesmo tempo;
  4. Tente maximizar o número de pontos num único batch para a placa de vídeo.

Lembrando n precisa em se preocupar em destruir objetos , quando eles n sao usados o propio GC faz isto para vc .

Muito obrigado pela dica. Certamente irá ajudar bastante.

O software que pretendo desenvolver é um programa de Geometria interativo em que o usuário manipula figuras geométricas na tela. Tudo fica um pouco mais complexo por que ainda não estou tão familiarizado com o Swing. Por exemplo, manipular botões, caixas de texto em uma IDE como o Netbeans e atribuir comportamentos para esses controles é relativamente fácil. O problema é quando você precisa refinar mais o comportamento, gerar componentes personalizados…

Mas gradativamente, com as dicas que recebi, tenho certeza que a dificuldade inicial irá desaparecer.