Foros del Web » Programación para mayores de 30 ;) » Java »

Liberar Memoria ModelAndView

Estas en el tema de Liberar Memoria ModelAndView en el foro de Java en Foros del Web. Hola a todos, tengo una aplicación con Java/Spring y estamos teniendo problemas de uso de recursos (Memoria), ojalá puedan ayudarme. El problema es con un ...
  #1 (permalink)  
Antiguo 13/07/2010, 07:47
Avatar de Wayern  
Fecha de Ingreso: septiembre-2008
Ubicación: Aguascalientes
Mensajes: 65
Antigüedad: 15 años, 7 meses
Puntos: 4
Pregunta Liberar Memoria ModelAndView

Hola a todos, tengo una aplicación con Java/Spring y estamos teniendo problemas de uso de recursos (Memoria), ojalá puedan ayudarme.
El problema es con un JSP que se exporta a excel, al parecer no está soltando la memoria después de hacer la petición y crear el archivo. El controlador utiliza el ModelAndView de Spring y en teoría al acabar de pintar el JSP debe liberar la memoria.
Este es el método que utilizo para traer el archivo de excel:
Código:
public ModelAndView exportOpenErrors(final HttpServletRequest request,
			final HttpServletResponse response) throws BException {
		final ModelAndView mav = new ModelAndView(successView + "Excel");
		final SimpleDateFormat format = new SimpleDateFormat(
				DataPattern.OUTPUT_TIME_EXCEL.getPattern());

		ApplicationContext ctx = this.getApplicationContext();
		DisplayOpenErrorsSvc displayExeSvc = (DisplayOpenErrorsSvc) ctx
				.getBean("displayOpenErrorsSvc");

		final Map<String, String> filters = new HashMap<String, String>();
		final String opGL = request.getParameter(InboundField.OP_GL.get());
		final String refId = request.getParameter(InboundField.REF_ID.get());
		final String receivedAfter = request
				.getParameter(InboundField.RECEIVED_AFTER.get());
		final String countryIsoCode = request
				.getParameter(InboundField.COUNTRY_ISO_CODE.get());
		List<String> selFilters = new ArrayList<String>();
		String avFilters[] = { "Operating GL", "Country", "Received After",
				"Ref ID" };
		selFilters.add(opGL);
		selFilters.add(countryIsoCode);
		selFilters.add(receivedAfter);
		selFilters.add(refId);

		if (opGL != null
				&& opGL.matches(DataPattern.GL_IDENTIFIER.getPattern())) {
			filters.put(InboundField.OP_GL.get(), opGL);
		}

		if (receivedAfter != null
				&& receivedAfter.matches(DataPattern.DATE_SHORT_DASHED
						.getPattern())) {
			filters.put(InboundField.RECEIVED_AFTER.get(), receivedAfter);
		}

		if (countryIsoCode != null
				&& (countryIsoCode.matches(DataPattern.WORD.getPattern()) || countryIsoCode
						.matches(DataPattern.WHITESPACE.getPattern()))
				&& !IfConstant.DEFAULT_SELECT.get().equals(countryIsoCode)) {
			filters.put(InboundField.COUNTRY_ISO_CODE.get(), countryIsoCode);
		}

		if (refId != null && (refId.matches(DataPattern.WORD.getPattern()))) {
			filters.put(InboundField.REF_ID.get(), refId);
		}
		List<VErrorView> transList = displayExeSvc.getTransErrors(filters,
				(BillerSecuritySvc) request.getSession().getAttribute(
						SecurityConstants.USER_SECURITY));
		Date date = new Date();

		mav.addObject("tList", transList);
		mav.addObject("date", format.format(date));
		mav.addObject("selFilters", selFilters);
		mav.addObject("filters", avFilters);
Mi SVC (DisplayOpenErrorsSvc) tiene un scope prototype para que por cada request cree un objeto nuevo y luego lo destruya, y así evitar que este usando el mismo, lo mismo hago con el DAO que utiliza el service:
Código:
<bean
        id="displayOpenErrorsSvc"
        parent="txProxyTemplate"
        scope="prototype">
        <property
            name="target">
            <bean
                class="com.org.corporate.jvsone.interfaces.service.impl.DisplayOpenErrorsSvcImpl"
                autowire="byName" />
        </property>
    </bean>
Código:
<bean
        id="transactionDao"
        class="com.org.corporate.jvsone.interfaces.dao.impl.TransactionDaoImpl"
        parent="daoTmpl"
        scope="prototype" />
Usando jconsole (La herramienta que viene dentro del JDK) puedo monitorear la memoria. En un principio veo que el JSP toma cierta cantidad de memoria, pero no la libera toda una vez que el JSP ya fue exportado a Excel, así que si se vuelve a generar el archivo toma más y más recursos. Mi duda básicamente es, ¿cómo indicarle a Java que debe liberar los recursos tomados por el JSP? Gracias de antemano.
  #2 (permalink)  
Antiguo 14/07/2010, 11:05
Avatar de Wayern  
Fecha de Ingreso: septiembre-2008
Ubicación: Aguascalientes
Mensajes: 65
Antigüedad: 15 años, 7 meses
Puntos: 4
Exclamación Respuesta: Liberar Memoria ModelAndView

Hola de nuevo. Después de mucho estrés encontré la solución a este problema de la liberación de memoria. No es la más elegante (Creo yo), pero si fue efectiva, por si alguna vez necesitan hacer algo similar, aquí está la respuesta.


Código:
<%@ page language="java"
	contentType="application/vnd.ms-excel; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%
	Date date=new Date();
	SimpleDateFormat dFormat=new SimpleDateFormat("dd-MMM-yyyy");
	response.addHeader("Content-Disposition",
			"attachment;filename=\"GBS Biller Inbound Errors "+dFormat.format(date)+".xls\"");
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@page import="java.util.Date"%>
<%@page import="java.text.DateFormat"%>
<%@page import="java.text.SimpleDateFormat"%>
<html>
<head>

<title>Open Errors</title>
</head>
<body>
<div id="document" style="position: relative; left: 30px">
<table cellpadding="0" cellspacing="0" border="0">
	<tr>
		<td>
			<table cellpadding="0" cellspacing="0" border="0">
				<tr>
					<td id="mainCell">
					<h6 id="pageTitle" style="font-size: 12pt; color: #3B73B9;">Open
					Errors</h6>
					<br>
					<div></div>
					</td>
					
				</tr>
			</table>
		</td>
		<td colspan="9">&nbsp;</td>
	</tr>
	<tr>
		<td>
			<table cellpadding="0" cellspacing="0" border="0">
				<c:forEach items="${selFilters}" var="filter" varStatus="index">
					<c:set var="fil" value="${filters[index.count-1]}"/>
					<tr  style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; color: #3B73B9; font-weight: bold">
						<td align="left">${fil}</td>
						<c:catch var="cException">
							<c:set var="isNum" value="${filter/1}" />											
						</c:catch>
							<c:choose>
									<c:when test="${filter!=null && filter!='select'}">
										<c:choose>
											<c:when test="${cException==null}">
												<td align="left" style="mso-number-format:\@">${filter}</td>
											</c:when>
											<c:otherwise>
												<td align="left">${filter}</td>
											</c:otherwise>
										</c:choose>
									</c:when>
									<c:otherwise>
									<td align="left">
										N/A
									</td>
									</c:otherwise>
							</c:choose>
					</tr>
				</c:forEach>
			</table>
		</td>
	</tr>
	<tr rowspan="2">
		<td>&nbsp;</td>
	</tr>
</table>
<br>
<br>
<table style="position: relative; left: 30px" width="100%" border="1">
	<thead>
		<tr>
			<th colspan="56" style="color: #3B73B9;" align="left">Transaction Errors</th>
		</tr>
		<tr style="font-family: Arial, Helvetica, sans-serif; font-size: 10px; color: #FFFFFF; background-color: #3B73B9">
			<th>Nb</th>
			<th>TRANS_SEQ_ID</th>
			<th>HDR_TRLR_SEQ_ID</th>
			<th>SENDING_GL</th>
			<th>OP_GL</th>
			<th>CREATE_DATE</th>
			<th>CREATE_TIME</th>
			<th>REC_TYPE</th>
			<th>REC_NUMBER</th>
			<th>ME</th>
			<th>GOLD_ID</th>
			<th>COUNTRY_ISO_CODE</th>
			<th>PL_NUMBER</th>
			<th>BRIN_BALANCING_SEGMENT</th>
			<th>BRIN_COST_CENTER</th>
			<th>BRIN_REFERENCE_ID</th>
			<th>PROJECT</th><th>ACCOUNT</th>
			<th>STAT_LOCAL_CURRENCY</th>
			<th>STAT_LOCAL_AMT</th>
		</tr>
	</thead>
	<tbody>
		<c:forEach items="${tList}" var="trans" varStatus="index">
			<c:set var="pat" value="${patterns[index.count-1]}" scope="request"/>
			<tr style="font-family: Arial, Helvetica, sans-serif; font-size: 10px;">
				<td>${index.count}</td>
				<td><c:out value="${trans.transSeqId}">${trans.transSeqId}</c:out></td>
				<td><c:out value="${trans.hdrTrlr}">${trans.hdrTrlr}</c:out></td>
				<td><c:out value="${trans.sendingGl}">${trans.sendingGl}</c:out></td>
				<td><c:out value="${trans.opGl}">${trans.opGl}</c:out></td>
				<td><c:out value="${trans.createDate}">${trans.createDate}</c:out></td>
				<td><fmt:formatDate  value="${trans.createTime}" type="time" pattern="HH:mm:ss" /></td>
				<td><c:out value="${trans.recType}">${trans.recType}</c:out></td>
				<td style="mso-number-format:\@"><c:out value="${trans.recNumber}">${trans.recNumber}</c:out></td>
				<td><c:out value="${trans.me}">${trans.me}</c:out></td>
				<td><c:out value="${trans.goldId}">${trans.goldId}</c:out></td>
				<td><c:out value="${trans.countryIsoCode}">${trans.countryIsoCode}</c:out></td>
				<td style="mso-number-format:\@"><c:out value="${trans.plNumber}">${trans.plNumber}</c:out></td>
				<td><c:out value="${trans.brinBalancingSegment}">${trans.brinBalancingSegment}</c:out></td>
				<td><c:out value="${trans.brinCostCenter}">${trans.brinCostCenter}</c:out></td>
				<td style="mso-number-format:\@"><c:out value="${trans.brinReferenceId}">${trans.brinReferenceId}</c:out></td>
				<td style="mso-number-format:\@"><c:out value="${trans.project}">${trans.project}</c:out></td>
				<td style="mso-number-format:\@"><c:out value="${trans.account}">${trans.account}</c:out></td>
				<td><c:out value="${trans.statLocalCurrency}">${trans.statLocalCurrency}</c:out></td>
				<td style="mso-number-format:${pat};">${trans.statLocalAmt}</td>
			</tr>
		</c:forEach>
		<c:set var="tList" value="${null}" scope="request"/>
		<c:set var="patterns" value="${null}" scope="request"/>
		<c:set var="date" value="${null}" scope="request"/>
		<c:set var="selFilters" value="${null}" scope="request"/>
		<c:set var="filters" value="${null}" scope="request"/>
		
		<c:remove var="tList" scope="request" />
		<c:remove var="patterns" scope="request" />
		<c:remove var="date" scope="request" />
		<c:remove var="selFilters" scope="request" />
		<c:remove var="filters" scope="request" />
	</tbody>
</table>
</body>
</html>
Lo que hice fue simplemente hacer null los objetos y las listas que estaba utilizando para crear mi JSP (Con c:set) y luego remuevo los objetos con el tag <c:remove> (Código en negrita), esos mismos objetos son los que se pasan desde el controlador (Ver mensaje original); por alguna razón el ModelAndView al momento de desplegar el JSP no estaba soltando la memoria de los objetos que utiliza, supongo que esto pasa porque los objetos son inalcanzables, pero al no ser nulos el Garbage Collector los deja vivir más, con lo que la memoria no es liberada con la rapidez que se necesitaba. Al momento de settear null los objetos, el GC está listo para tomarlos.

Si tienen una mejor solución, compartanla! . Saludos.
  #3 (permalink)  
Antiguo 15/07/2010, 03:49
 
Fecha de Ingreso: febrero-2010
Mensajes: 128
Antigüedad: 14 años, 2 meses
Puntos: 3
Respuesta: Liberar Memoria ModelAndView

Puedes aumentar la capacidad de la memoria de la jvm...

También puedes forzar el garbage collector o métodos similares, aunque se supone que se pasan automáticamente...

nose...

me alegro que encontraras la solución
  #4 (permalink)  
Antiguo 15/07/2010, 04:21
Avatar de elAntonie  
Fecha de Ingreso: febrero-2007
Mensajes: 894
Antigüedad: 17 años, 2 meses
Puntos: 10
Respuesta: Liberar Memoria ModelAndView

Wenas

Solo escribo para indicar que, aunque el gc tenga un metodo al que se puede invocar para que pase en ese momento, la realidad es que no lo hace.

El gc pasa automaticamente cuando la jvm lo requiere, invocar manualmente (ignoro si sigue pudiendo hacerse) no solo es contraproducente sino que no sirve para nada.

El modo de hacer que el gc funciones, es que no existan referencias a esos objetos. Asi que la unica solucion es poner a null, tal y como ha hecho Wayern.

Saludos.
__________________
--
NO. Tu problema no es urgente.

CCFVLS
  #5 (permalink)  
Antiguo 15/07/2010, 16:19
Avatar de Wayern  
Fecha de Ingreso: septiembre-2008
Ubicación: Aguascalientes
Mensajes: 65
Antigüedad: 15 años, 7 meses
Puntos: 4
Exclamación Respuesta: Liberar Memoria ModelAndView

Cita:
Iniciado por elAntonie Ver Mensaje
Wenas

Solo escribo para indicar que, aunque el gc tenga un metodo al que se puede invocar para que pase en ese momento, la realidad es que no lo hace.

El gc pasa automaticamente cuando la jvm lo requiere, invocar manualmente (ignoro si sigue pudiendo hacerse) no solo es contraproducente sino que no sirve para nada.

El modo de hacer que el gc funciones, es que no existan referencias a esos objetos. Asi que la unica solucion es poner a null, tal y como ha hecho Wayern.

Saludos.
Había escuchado algo de eso, que es contraproducente llamar al System.gc(), aunque para ser sinceros nunca he investigado por qué.
Gracias por sus comentarios.

Etiquetas: liberar, memoria
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 10:32.