Vraptor 3 - Heap Space Out of Memory

Estou a cerca de 1 mês atuando na migração (para Vraptor 3) de um módulo que foi escrito com Vraptor 2.

Deu um pouco de trabalho, mas migrei sem maiores problemas, a surpresa veio após o fim da migração.

Com o inicio dos testes, comecei a perceber que o servidor de aplicação Jboss(Acontece no Tomcat também) estava ocorrendo erro de Java Heap Space Out of Memory.

Fiz download do Visual Vm, e o que descobri é que os objetos ficam instanciados mesmo após o fim da execução, detalhe se uso 20 instancias de objetos para montar uma tela, quando aperto F5 para atualizar este numero dobra.

Mapeamento da aplicação pelo Visual Vm, abaixo seguem as instâncias abertas após abrir a aplicação.

Combo(Domain) 8(Instâncias abertas) => equivale a 8 registros que carregam os combos da tela.
MorteBeneficiariosController 1(Instâncias abertas)
MorteBeneficiariosService 1(Instâncias abertas)

Todas estes instâncias não deveriam ser apagadas após montar a tela?

Seguem abaixo informações do desenvolvimento:

Controller

[code]import java.util.Vector;

import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.ioc.RequestScoped;

@Resource
@RequestScoped
public class MorteBeneficiariosController {

private Result result;
private Vector<Combo> vector;
String strRetorno;

public MorteBeneficiariosController(Result result) {
	this.result = result;
}


public id index() {
	
	//Popula os combos da tela
	vector = new MorteBeneficiariosService().listaCmbEstadoCivil();
	result.include("estadosCivis", vector);
	
	vector = new MorteBeneficiariosService().listaCmbDescendentes();
	result.include("descendentes", vector);
	
	vector = null;
	
}

public id simulador(String idEstadoCivil, String idDescendentes) {
	
	//Executa o simulador
	strRetorno = new MorteBeneficiariosService().simulaMorteBeneficiarios(idEstadoCivil+";"+idDescendentes);
	result.include("beneficiarioSimulado", strRetorno);
	
}

}[/code]

Service

[code]import java.util.HashMap;
import java.util.Vector;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.RequestScoped;

@Component
@RequestScoped
public class MorteBeneficiariosService {

private Vector<Combo> vectorCombo;
private Combo combo;
private HashMap hm;


public Vector<Combo> listaCmbEstadoCivil() {
	
	vectorCombo = new Vector<Combo>();
	
	combo = new Combo("", "-- Selecione --");
	vectorCombo.add(combo);
	
	combo = new Combo("1", "Casado(a)");
	vectorCombo.add(combo);
	
	combo = new Combo("2", "Solteiro(a) sem companheiro(a)");
	vectorCombo.add(combo);
	
	return vectorCombo;
}



public Vector<Combo> listaCmbDescendentes() {
	
	vectorCombo = new Vector<Combo>();
	
	combo = new Combo("", "-- Selecione --");
	vectorCombo.add(combo);
	
	combo = new Combo("1", "Deixando descendentes");
	vectorCombo.add(combo);
	
	combo = new Combo("2", "Deixando descendentes pré-mortos");
	vectorCombo.add(combo);
	
	combo = new Combo("3", "Sem deixar descendentes");
	vectorCombo.add(combo);
	
	combo = new Combo("4", "Sem deixar descendentes e ascendentes");
	vectorCombo.add(combo);
	
	return vectorCombo;
}


public String simulaMorteBeneficiarios(String chaveBusca) {
	
	hm = new HashMap();
	
	hm.put("1;1", "Cônjuge e Descendentes");
	hm.put("1;2", "Cônjuge e Herdeiros Legais dos Descendentes pré-mortos");
	hm.put("1;3", "Cônjuge e Ascendentes");
	hm.put("1;4", "Somente o Cônjuge");
	hm.put("2;1", "Somente o(s) Descendente(s)");
	hm.put("2;2", "Herdeiros Legais dos Descendentes pré-mortos");
	hm.put("2;3", "Os Ascendentes");
	hm.put("2;4", "Colaterias na seguinte ordem: Irmãos, Sobrinhos, Tios e Primos");
	
	return hm.get(chaveBusca).toString();
}

}[/code]

JSP

[code]<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c” %>

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
</head>

<body>
	<form name="form-simulador">

	<h1>Morte Beneficiários</h1>
	
	<div class="divCaixaInformacaoBordaGrande">

		<div class="divCaixaInformacaoBorda">
		
			<div class="fundoCabecalho16">&nbsp;Simulador</div>
			
			<div class="divCaixaInformacaoLinha">&nbsp;</div>
			
			<div class="divFormularioCaixa">
				Segurado(a) falecido(a) no estado civil de 
				<select id="idEstadoCivil" name="idEstadoCivil">
					<c:forEach var="estadoCivil" items="${estadosCivis}">
						<option value="${estadoCivil.id}">${estadoCivil.descricao}</option>
					</c:forEach>
				</select>, 
				e 
				<select id="idDescendentes" name="idDescendentes">
					<c:forEach var="descendente" items="${descendentes}">
						<option value="${descendente.id}">${descendente.descricao}</option>
					</c:forEach>
				</select>
				<div id="beneficiarioSimulado" class="divAlertaFaltaInformacao">&nbsp;</div>
			</div>
			
		</div>
		
		<div class="divCaixaInformacao">
			<div class="fundoCabecalho14">&nbsp;Observa&ccedil;&otilde;es</div>	
		</div>
	
	</div>
	</form>
</body>
[/code]

Web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Simuladores</display-name> <filter> <filter-name>vraptor</filter-name> <filter-class>br.com.caelum.vraptor.VRaptor</filter-class> </filter> <filter-mapping> <filter-name>vraptor</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping> </web-app>

Libs - Libs que estou utilizando
aopalliance.jar
aspectjrt.jar
commons-collections-3.2.1.jar
commons-logging.jar
guava-r07.jar
iogi-0.9.1.jar
javassist-3.14.0.GA.jar
jstl-api-1.2.jar
jstl-impl-1.2.jar
log4j-1.2.16.jar
mirror-1.5.1.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.aspects-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
paranamer-2.2.jar
scannotation-1.0.3.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1.jar
vraptor-3.4.1.jar
xstream-1.3.1.jar

Este é um projeto menor, que também ocorre erro.

Alguém poderia me ajudar? O que estou fazendo de errado?

Desde já agradeço

Algumas melhorias que vc pode fazer:

  • esse MorteBeneficiarioService pode ser @ApplicationScoped, já que ele retorna dados fixos
  • como esse service é um @Component, receba-o no construtor! Não dê new nesse service.
  • calcule as listas dos métodos apenas uma vez
  • Use ArrayList ao invés de Vector… não há motivo nenhum pra usar vector nesse caso. Vector é sincronizado, nos casos em que ele seria indicado, é melhor usar uma synchronizedList.

[quote=Lucas Cavalcanti]Algumas melhorias que vc pode fazer:

  • esse MorteBeneficiarioService pode ser @ApplicationScoped, já que ele retorna dados fixos
  • como esse service é um @Component, receba-o no construtor! Não dê new nesse service.
  • calcule as listas dos métodos apenas uma vez
  • Use ArrayList ao invés de Vector… não há motivo nenhum pra usar vector nesse caso. Vector é sincronizado, nos casos em que ele seria indicado, é melhor usar uma synchronizedList.[/quote]

Muito obrigado pelo retorno Lucas.

Fiz as alterações conforme sua sugestão, porém o erro continua.

Minha preocupação maior é com os objetos que montam a tela(JSP), continuarem instanciados mesmo após o final da execução?

Por exemplo:

É como se os objetos da EL que estão na JSP “${estadosCivis} é um deles” ficassem com referência na memória fulltime, e a cada nova requisição mais objetos instanciados.

Já implementei um método no Controller com a anotação @PreDestroy, para tentar destruir as referências, tentei com outros containers, hoje está com Spring, mas já foi testado Guice e Picocontainer.

Não obtive sucesso em nenhuma situação, os objetos continuam instanciados na memória.

Alguma outra sugestão?

Desde já agradeço

cara, isso é o normal no java. A menos que alguém mantenha a referência ao objeto, ele é garbage collected uma hora ou outra…

vc mudou a classe para @ApplicationScoped e parou de dar new na classe? tá recebendo ela no construtor dos controllers?

[quote=Lucas Cavalcanti]cara, isso é o normal no java. A menos que alguém mantenha a referência ao objeto, ele é garbage collected uma hora ou outra…

vc mudou a classe para @ApplicationScoped e parou de dar new na classe? tá recebendo ela no construtor dos controllers?[/quote]

Sim mudei para @ApplicationScoped e também não estou mais dando new no controller.

Lucas quanto as referências, fiz o seguinte teste:

1º - Carreguei a página no Browser e foram instanciados 8 Objetos combos, 1 Controller e 1 Service. estou verificando com o VisualVm.
2º - Fechei o Browser e fiquei duas horas acompanhando pelo VisualVm.
3º - Após todos este tempo, sem nenhum acesso, pois estou fazendo este teste em desenvolvimento, todas as instâncias continuam com referenciadas.

Isso é normal. Ele só vai remover as instâncias quando rodar o garbage collector… que ele faz em horas aleatórias, e quando ele precisa de memória…

o problema é se ficar criando instancias toda hora e ele nunca coletá-las.