Details
Description
I am using Velocity in a J2EE application. I had problems with my application
leaking memory. I have traced this back to Velocity. I have made a little simple
JUnit test, which demonstrates this memory leak. It seems that every time you
instantiate a Velocity Engine with a resource loader it leaks about 1.5 Kb of
heap memory. If I do not include the setup of the resource loader from
properties, there is no leak.
I found this in Velocity 1.3, but I have tried the same test with a cvs checkout
of Velocity from 4th of marts 2003, and it showed the same problem. If I let the
test run with a max heap size of 64Mb, it will fail with OutOfMemoryError
exception after about 34.000 iterations.
I have attached the JUnit.
Cheers, Kim Madsen
Below follows my unit test
________________________________________________________________________
package com.inceptor.rt;
import com.inceptor.base.ExceptionBase;
import com.inceptor.service.DiagnosticsFact;
import com.inceptor.service.DiagnosticsIf;
import com.inceptor.util.Test;
import com.inceptor.util.TestSuite;
import com.inceptor.util.TestCaseJUnit;
import com.inceptor.util.Various;
import java.io.StringWriter;
import java.util.Properties;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
import org.apache.velocity.app.VelocityEngine;
/** Servlet used to test <code>rt/Servlet</code> functionality.
*
- @version $Id: VelocityMemorySimple.java,v 1.3 2003/02/28 17:28:52 kim Exp $
*/
public class VelocityMemorySimple
extends TestCaseJUnit {
private static final DiagnosticsIf diag =
DiagnosticsFact.instance(VelocityMemorySimple.class);
private static final int ROWS_BETWEEN_DISPLAY = 1000;
private static final int ROWS_TO_ITERATE = 50000 * ROWS_BETWEEN_DISPLAY;
private static long lastTime = -1;
public VelocityMemorySimple(String name) throws ExceptionBase
{ super(name); }///////////////////////////////////////////////////////////////////
private void showInfo(long rowsInserted)
throws Exception {
if (rowsInserted==0)
{ System.gc(); lastTime = System.currentTimeMillis(); }if (rowsInserted%ROWS_BETWEEN_DISPLAY == 0)
{ long nowTime = System.currentTimeMillis(); System.gc(); diag.info("Ite=" + rowsInserted + " Mem free =" + java.lang.Runtime.getRuntime().freeMemory() + " Mem total=" + java.lang.Runtime.getRuntime().totalMemory() + " Ite/sec.=" + ((double) 1000*ROWS_BETWEEN_DISPLAY)/(nowTime-lastTime) ); lastTime = nowTime; }}
public void testMemory()
throws Exception {
try {
Properties p = new Properties();
p.setProperty("runtime.log.logsystem.class",
"org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
p.setProperty("runtime.log.logsystem.log4j.category", "VELOCITY");
p.setProperty("resource.manager.logwhenfound", "true");
p.setProperty("velocimacro.library", "");
p.setProperty("resource.loader",
"datasourceglobal, datasourcecustom");
p.setProperty("datasourceglobal.resource.description",
"Load Templates From java:ExcediaDB Global Resources");
p.setProperty("datasourceglobal.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader");
p.setProperty("datasourceglobal.resource.loader.resource.datasource",
"java:ExcediaDB");
p.setProperty("datasourceglobal.resource.loader.resource.table",
"RESOURCEGLOBALS");
p.setProperty("datasourceglobal.resource.loader.resource.keycolumn",
"NAMESTR");
p.setProperty("datasourceglobal.resource.loader.resource.templatecolumn",
"CONTENTCHARACTER");
p.setProperty("datasourceglobal.resource.loader.resource.timestampcolumn",
"MODIFICATIONTIME");
p.setProperty("datasourceglobal.resource.loader.resource.cache",
"true");
p.setProperty("datasourceglobal.resource.loader.resource",
"6");
p.setProperty("datasourcecustom.resource.description",
"Load Templates From java:ExcediaDB Custom Resources");
p.setProperty("datasourcecustom.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader");
p.setProperty("datasourcecustom.resource.loader.resource.datasource",
"java:ExcediaDB");
p.setProperty("datasourcecustom.resource.loader.resource.table",
"RESOURCECUSTOMS");
p.setProperty("datasourcecustom.resource.loader.resource.keycolumn",
"NAMESTR");
p.setProperty("datasourcecustom.resource.loader.resource.templatecolumn",
"CONTENTCHARACTER");
p.setProperty("datasourcecustom.resource.loader.resource.timestampcolumn",
"MODIFICATIONTIME");
p.setProperty("datasourcecustom.resource.loader.resource.cache",
"true");
p.setProperty("datasourcecustom.resource.loader.resource",
"6");
VelocityContext context = null;
StringWriter sw = null;
VelocityEngine ve = null;
for (int i=0; i<=ROWS_TO_ITERATE; i++)
{ showInfo(i); ve = new VelocityEngine(); ve.init(p); }} catch (OutOfMemoryError e)
{ diag.error(e); throw e; }}
public static Test suite() throws Exception
{ diag.debug("Setup test suite"); TestSuite suite = new TestSuite(); suite.addTest(new VelocityMemorySimple("testMemory")); return suite; }}