BigDecimal e limpeza de memória

9 respostas
R

Ola pessoal, estou com duas duvidas de principiante e se puderem, como sempre, me ajudar agradeço. Primeiro quero saber se do ponto de vista de consumo de memória esta correto fazer como estou fazendo no código abaixo, ou seja, estou retornando a soma de varias resultados de métodos que são do tipo BigDecimal, esta soma é concatenada direto no return, funciona, mas minha duvida é se é o mais correto a ser feito? if (tipo.equals("NAO")) { return TotalCalculaNao(nota).add( TotalInterc(nota).add( TotalCred(nota).subtract( TotalDeb(nota)))); }
Outra duvida é se para melhor uso da memória eu devo colocar um finally e atribuir null para todos os objetos usados no método, para caso de não serem mais utilizados possam ser limpados da memória? Ex:

private BigDecimal TotalCred(Nota nota) throws FalhaDaSomaMoedaException { try { nota.setTipo("CRE"); resl = lancamentoDao.somaNotasTipoCredDeb(nota); return resl; } catch (DAOException e) { e.printStackTrace(); throw new FalhaDaSomaMoedaException(); } finally{ resl = null; } }

9 Respostas

E
  1. Está OK assim, já que depois do garbage collection deve sobrar só um BigDecimal, que é o que é retornado por esse método.

reisah:
return TotalCalculaNao(nota).add( TotalInterc(nota).add( TotalCred(nota).subtract( TotalDeb(nota)))); }

2) O finally é executado sempre, mesmo que você faça o return. Na verdade, neste caso em particular, ele é executado depois do return (parece esquisito, não?). Veja o que ocorre.

import java.math.BigDecimal;

class TesteFinally {
    private BigDecimal resl;
	public BigDecimal soma (BigDecimal bd1, BigDecimal bd2) {
	    try {
		    resl = bd1.add (bd2);
		    return resl;
		} finally {
		    resl = null;
		}
	}
	public static void main (String[] args) {
	    TesteFinally tf = new TesteFinally();
		// Imprime 10.23
		System.out.println (tf.soma (new BigDecimal ("2.34"), new BigDecimal ("7.89")));
		// Imprime null
		System.out.println (tf.resl);
	}
}
sergiotaborda

reisah:
Ola pessoal, estou com duas duvidas de principiante e se puderem, como sempre, me ajudar agradeço. Primeiro quero saber se do ponto de vista de consumo de memória esta correto fazer como estou fazendo no código abaixo, ou seja, estou retornando a soma de varias resultados de métodos que são do tipo BigDecimal, esta soma é concatenada direto no return, funciona, mas minha duvida é se é o mais correto a ser feito? if (tipo.equals("NAO")) { return TotalCalculaNao(nota).add( TotalInterc(nota).add( TotalCred(nota).subtract( TotalDeb(nota)))); }

Está correto e é assim mesmo que deve ser usado. Esta forma de encadear as chamadas é um padrão chamado Method Chain. Não é usual nas API java , mas existe em alguns pontos. o BigDecimal e BigInteger são uns, a interface Appendable e suas implementações como StringBuilder e StringBuffer são outros. Sempre que puder dê prioridade para este tipo de escrita inclusive em classes que vc construa.

Isto não é necessário ( e como exemplificado pode dar resultados q vc não espera). Vc está preocupa em “limpar a casa” isso é muito louvável, mas o java cuida disso para vc.
Em java sempre que vc abre { vc está criando um escopo de variáveis. Sempre que esse escopo termina com } essas variáveis são jogadas fora. Portanto, quando o método termina (em }) todas as variáveis internas ao método vão para o lixo.
Um código melhor , que não deixa margem para duvidas, seria assim

private BigDecimal TotalCred(Nota nota) throws FalhaDaSomaMoedaException {  
            try {  
                nota.setTipo("CRE");  
                return lancamentoDao.somaNotasTipoCredDeb(nota);  
            } catch (DAOException e) {  
                throw new FalhaDaSomaMoedaException(e);  
            }  
        }

simples. vc simplesmente não cria uma variável :slight_smile:

P.S. Note a diferença de tratamento de erro dentro do catch. Isso é mais importante que anular as variáveis.

E

Setar uma variável para null parece ser um costume de quem já programou em VB 6.0 alguma vez na vida. Você tem de ficar fazendo coisas como:

Dim Bla As  New XXX()
...
Set Bla = Nothing

Isso é um porre, mas era meio que obrigatório, porque o VB 6.0 não tinha regras muito óbvias para o tempo de vida de objetos. E no fim das contas você acabava forçando a barra e setando tudo para Nothing (que é o equivalente do null em Java).

R

Pessoal, obrigado pela ajuda, estão ajudando muito, a opção por setar os objetos para null eu encontrei aqui mesmo no fórum, mas não sabia até que nível eu deveria ir, se ser radical e setar tudo para null ou apenas alguns objetos, pois minha aplicação é simples mas esta consumindo muita memória, então estou tentando refinar ao máximo minha aplicação e já aproveitar para aprender boas praticas.

R

Completando com mais uma duvida, seguindo a ideia do sergiotaborda, o que é correto fazer se em uma classe de serviço eu tenho dois métodos e nestas classes uso um objeto apenas temporariamente para executar um método qual é a melhor pratica, criar este objeto duas vezes uma em cada método como fiz no exemplo abaixo, ou cria-lo no inicio da classe e depois de cada uso no método, setar null, ou nem isso?

public void atualizarDataPagamento(int codForn, Date dataPag) throws FalhaDeInclusaoException { CadastroDeDataPagamento cdp = new CadastroDeDataPagamento(); dp = cdp.buscaDataPagamento(codForn, dataPag); dp.setPago(true); cdp.salvar(dp); cdp=null; }

E

Neste método em particular, o uso de “cdp = null” é dispensável, porque imediatamente essa variável sai fora de escopo.

Entretanto, você tem uma variável “dp” que imagino que seja uma variável membro dessa classe. Se for, e você não estiver reusando esse valor “dp”, você tem de anular essa variável dp. Ou seja, evite ao máximo estender desnecessariamente o escopo de variáveis (prefira variáveis locais a variáveis membro) se você não for reusar o valor delas.

public void atualizarDataPagamento(int codForn, Date dataPag)  
        throws FalhaDeInclusaoException {  
    CadastroDeDataPagamento cdp = new CadastroDeDataPagamento();  
    dp = cdp.buscaDataPagamento(codForn, dataPag);  
    dp.setPago(true);  
    cdp.salvar(dp);  
    cdp=null;         // esta linha pode ser removida
    dp = null; // acresentar isto se você não estiver usando dp para outra coisa
}
R

Legal entanglement, era isso que eu queria saber, tenho varias variaveis que não reutilizo valor, e não sabia qual seria o procedimento correto para fazer. Obrigado.

sergiotaborda

reisah:
Completando com mais uma duvida, seguindo a ideia do sergiotaborda, o que é correto fazer se em uma classe de serviço eu tenho dois métodos e nestas classes uso um objeto apenas temporariamente para executar um método qual é a melhor pratica, criar este objeto duas vezes uma em cada método como fiz no exemplo abaixo, ou cria-lo no inicio da classe e depois de cada uso no método, setar null, ou nem isso?

public void atualizarDataPagamento(int codForn, Date dataPag) throws FalhaDeInclusaoException { CadastroDeDataPagamento cdp = new CadastroDeDataPagamento(); dp = cdp.buscaDataPagamento(codForn, dataPag); dp.setPago(true); cdp.salvar(dp); cdp=null; }

Sempre que vc der new em serviços é um sidrome de má escolha de escopo. o codigo acima deveria ser assim

class AlgumaClasseQueVcNaoDisseQualEra { 

 private CadastroDeDataPagamento cdp = new CadastroDeDataPagamento();

public void atualizarDataPagamento(int codForn, Date dataPag)
			throws FalhaDeInclusaoException {
		
		DataPagamento dp = cdp.buscaDataPagamento(codForn, dataPag);
		dp.setPago(true);

		cdp.salvar(dp);
	
	}

O dp é um dado o cdp é um serviço. O serviço tem um escopo maior e pode ser reutilizado em várias chamadas porque não tem estado. O resultado da busca é um objeto de dados e ele só vive enquanto é manipulado.

Esqueça esse negocio de igualar a null. Isso não é necessário em java.

E

De fato, olhando os fontes do JDK, vocês vão ver que há muito poucos lugares onde se seta explicitamente alguma coisa para null. O resto do tempo é resolvido com escopo.

O lugar no JDK onde isso é feito é, por exemplo, na limpeza de um ArrayList, porque nesse caso não é suficiente simplesmente ajustar os ponteiros de início e fim dos dados dentro de um array interno - ele limpa as posições correspondentes no ArrayList mesmo, para evitar referências indevidas.

Criado 5 de dezembro de 2012
Ultima resposta 6 de dez. de 2012
Respostas 9
Participantes 3