Liberar memória

6 respostas
K

Ola pessoal, meu problema é o seguinte estou desenvolvendo um joguinho para dispositivo móvel e sabemos que eles não possuem uma memoria muito grande, então imaginei o seguinte, criar uma tela de loading que teria a finalidade de remover as referencias e avisar ao coletor de lixo que se ele quiser ou for necessário pode limpar o lixinho usando o System.gc();.

O problema é o seguinte não posso tirar as referencias na classe game, vou explicar o porque, ele implementa a seguinte interface :
EnginerOption();
LoadResource();
CreateScene();
EnginerLoop();

Quando chega em CreateScene(); ela cria uma cena para por imagens então crio um objeto preload que por default no construtor ja cria como primeira cena o Menu. Até ai tudo bem, mas chegou o meu problema, se a pessoa clicar em Iniciar Game ela ira criar outro objeto (CarregarMapa) que carregara o mapa e inicia o jogo, logo o menu se torna inútil, pois já estamos em outra cena. Então eu queria deslocar recurso, mas na internet não encontrei nada que torne o objeto Menu um lixo para o coletor a não ser que aponte para NULL. Se eu fizer:

Menu menu = new Menu();
menu = null;

'-' vai criar e ja vai " perder a referencia e não é isso que queremos, preciso que o menu avise ou saiba quando ele se tornou inútil. O melhor jeito que encontrei foi esse colocar um metodo finalizar em todas as classes que serão limpadas

Programa teste
public class MyTeste {

	public boolean finalizar(boolean op){
		return op;
	}

}

E uma bela de uma gambiarra onde uma classe Object recebe um objeto genérico, copia os métodos da mesma e verifica se esta retornando true ou false se for true então retira a referencia do objeto, essa verificação irá ficar em um loop infinito que é o mesmo loop do GameEnginer;

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// TODO Auto-generated method stub
		myTeste = new MyTeste();
		teste(myTeste);
		 
	}
	
	public static void teste(Object op) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Class cls = op.getClass();
		Method metodo = cls.getMethod("finalizar", boolean.class);
		 
		o = new Object();
		 arg = new Boolean(false);
		 o = metodo.invoke(myTeste, arg);
		 System.out.print(o);
	}

Minha pergunta é tem uma maneira mais facil de dizer Menu você é lixo dentro do próprio menu? Ou outra maneira de setar NULL no menu?

Ja tentei o seguinte e não funcionou :
public void removerReferencia(Object o){
o = null;

[img]http://img208.imageshack.us/img208/7371/classdiagram1.jpg[/img]

6 Respostas

MarkKnopfler

Bem, pelo que entendi, é o menu que chama a próxima tela. Aí fica difícil mesmo, porque realmente o único jeito de se jogar algo no lixo no Java é setar a referência para null.

Eu modificaria a estrutura de classes, criando uma classe Controller que determina o fluxo de telas. Ao menu, caberia somente retornar a opção selecionada pelo usuário. Um exemplo de sequência de ações:

  • Controller mostra Menu
  • Usuário seleciona opção
  • Fluxo retorna para Controller
  • Controller faz menu = null
  • Controller inicia próxima tela de acordo com a opção
K

Bem, pelo que entendi, é o menu que chama a próxima tela. Aí fica difícil mesmo, porque realmente o único jeito de se jogar algo no lixo no Java é setar a referência para null.

Eu modificaria a estrutura de classes, criando uma classe Controller que determina o fluxo de telas. Ao menu, caberia somente retornar a opção selecionada pelo usuário. Um exemplo de sequência de ações:

  • Controller mostra Menu
  • Usuário seleciona opção
  • Fluxo retorna para Controller
  • Controller faz menu = null
  • Controller inicia próxima tela de acordo com a opção

Ótima ideia, verdade toda vez que chama uma cena no menu podemos volta pro controller que no caso ali é meu preload e inicia a outra cena “fechando” o menu é amanhã verei isso e se der tudo certo ou errado posto aqui. Obrigado :3

Victor_Neves

colega, ja que voce quer diminuir a quantidade de objetos, faz o seguinte, ao invés de voce escrever

public static void main(String[] args) { objTeste = new ObjTeste(); metodoTeste(objTeste); }

faça o seguinte

public static void main(String[] args) { metodoTeste(new ObjTeste()); }

isso ajuda.

ah! e dê uma olhada em padroes de projeto, veja se o padrão Flyweight te ajuda, ele costuma ajudar o pessoal de games…
voce usa esse padrao quando voce quer que uma instancia de uma classe possa ser usada para fornecer muitas “instancias virtuais”…

K

Vlw pela dica amigo sempre me esqueço disso, ja estou estudando isso também os Patterns né, nunca tinha pegado os padrões para ler 3 eu vivo fora dos padrões impostos pela sociedade rs

Sem brincadeiras to lendo esse aqui

Bom, acho que ja trabalhava com Flyweight sem saber, pois a UML a cima erá só para ilustrar meu problema, faço assim em meu jogo digamos que eu tenha uma classe inimigo e todo inimigo tem nome, vida e método colisão, isso é só um exemplo, mas nem todo inimigo é igual então faço uma classe genérica chamado inimigo coloco tudo o que eles tem de igual e depois crio classes menores estendidas de inimigo apenas adicionando a diferença no caso de uma classe dragão extends de inimigo e adiciono metodos como cospe fogo ou a de um leão saltar no player. Isso diminui o numero de objetos e métodos no caso ali todos tem o método finalize, mas eles irão estender de outra classe, não sei se é isso o Flyweight, mas pelo que li aqui

Parece que se coloca tudo em uma classe maior evitando criar varias classezinhas…Se for isso estou evitando, pois antigamente trabalhava dessa forma e virava uma bagunça =3

Sobre meu problema estou resolvendo da seguinte forma:
Preload é meu controle crio uma variável Context coloco meu contexto que é o preload no construtor do menu e chamo a função finalizar do menu para o preload quando a pessoa selecionar outra opção, não sei se vai dar certo, mas é isso que tentarei fazer.

B

Eu acho que você está se preocupando à toa, não com o fato manter o uso de memória num nível razoável, o que é uma boa prática, mas tendo que controlar o ciclo de vida de objetos fora do teu escopo manualmente, sem saber se você realmente precisa disso.

Minha pergunta: Quem te disse que o objeto de menu não vai ser descartado quando o jogo for para a próxima cena?

Mantendo uma boa prática de programação, declarando, criando e destruindo objetos dentro de um escopo curto, o uso de memória vai ser pequeno. Se for usar um cache de objetos, use um WeakReference, quando a coleta de lixo for executada, objetos descartáveis serão recolhidos.

Outra coisa: talvez você deve se preocupar não com o uso de memória, mas o tempo de limpeza dela durante uma coleta de lixo, que é capaz de ficar travando o teu jogo, ou diminuir a taxa de frames. Criar milhões de objetos descartáveis num escopo curto também vai te trazer problemas.

Meça o teu jogo não em frames por segundo, mas em quantos milisegundos demora para fazer um frame(que é renderização, mais inputs, mais processamento da cena, IA, rede, etc). Defina quanto de memória o teu jogo precisa pra rodar optimamente, sem usar muita CPU, mas também sem roubar toda a memória do sistema.

K

Minha pergunta: Quem te disse que o objeto de menu não vai ser descartado quando o jogo for para a próxima cena?
Eu li em vários livros que enquanto um objeto tiver uma referencia para ele por sua vez não será limpo pelo lixeiro. A cena sempre teria uma referencia no preload, mas o MarkKnopfler ja deu a solução que é quando clicar em Iniciar Game no menu isso vai ativar um método que esta no próprio preload (Preload é meu controle que sempre ficará ativo) chamando iniciarGame() e abaixo deste metodo terá

CarregarMapa carregarMapa =  new CarregarMapa();
carregarMapa.LoadMapa("mapa.xml");
menu = null; //Chamei outra cena e tirei a referencia do menu.

:smiley: ele resolveu bem a xaradinha

Outra coisa: talvez você deve se preocupar não com o uso de memória, mas o tempo de limpeza dela durante uma coleta de lixo, que é capaz de ficar travando o teu jogo, ou diminuir a taxa de frames. Criar milhões de objetos descartáveis num escopo curto também vai te trazer problemas.

Eu só me preocupo com o uso da memória de um mapa para outro, nesse tempo fica uma tela preta escrito CARREGANDO, ai removo as referencias de objetos que não uso mais e carrego outros mapas também uso o System.gc() ele diz para o lixeiro que se for necessário faça limpeza agora, se ele não limpar é porque não é necessário, vai depender de dispositivo para dispositivo, usar a menor quantidade de recurso sem perder qualidade no jogo, tanto é que nem faço uso de int, só uso byte e no máximo short. O que não quero é travamento nos celulares e poder ser instalado no maior número de celulares possíveis, mesmo que seja os mais antigos.

Meça o teu jogo não em frames por segundo, mas em quantos milisegundos demora para fazer um frame(que é renderização, mais inputs, mais processamento da cena, IA, rede, etc). Defina quanto de memória o teu jogo precisa pra rodar optimamente, sem usar muita CPU, mas também sem roubar toda a memória do sistema.
É uma boa dica , para não roubar toda a memoria pensei de usar imagens svg que da para salvar do tamanho de uma agulha e aumentar sem perda de qualidade, só que daria muito trabalho para estudar a biblioteca, por enquanto como é para aprendizagem, melhorar minhas praticas de programação vai jpg mesmo. De qualquer forma muito obrigado pela ajuda e pelas dicas.

Se alguém quiser conhecer o game e a tecnologia usada pode ir aqui:
http://www.unidev.com.br/phpbb3/viewtopic.php?f=5&t=55424
ou em meu blog


Criado 10 de novembro de 2012
Ultima resposta 10 de nov. de 2012
Respostas 6
Participantes 4