Hi, Florian
We could have a better idea if I can provide the following information:
1. Are you sure Tomcat is picking up Xalan 2.4.0 rather than JDK 1.4's
builtin Xalan (2.2.D11)? If not sure, you can use EnvironmentCheck to find
it out.
2. How many stylesheets (.xsl files) do you have?
3. Did all the requests run concurrently in different threads or
sequentially in one thread?
Morris Kwan
XSLT Development
IBM Toronto Lab
Tel: (905)413-3729
Email: [EMAIL PROTECTED]
"Florian
Deissenboeck" To: <[EMAIL PROTECTED]>
<[EMAIL PROTECTED] cc:
.de> Subject: Tomcat
out-of-memory-error when caching XSLT
11/27/2002 09:55
AM
Hi,
Tomcat dies with a java.lang.OutOfMemoryError if we cache stylesheets and
more than ~10 users access server simultaneously. The details:
We have simple servlet which does triggers XSLT transformation. The input
XML has ~50 lines, the XSLT has ~2000 lines. We did a load test with Apache
JMeter simulating 30 users accessing the server more or less
simultaneously.
If we do no caching at all the server survives but performance is poor. So
we wrote a small caching class which is very similar to the one presented
in
O'Reilly's "Java and XSLT"-Book. It uses a hashmap for template caching, I
attached class.
We first tried to use XSLTC
(transformerFactory = (new
org.apache.xalan.xsltc.trax.TransformerFactoryImpl()).newInstance();).
Performance increases rapidly but the server runs out of memory after ~300
accesses. Everything is ok for 1 to ~10 users. So we tried the classic
template thing
(transformerFactory =(new
org.apache.xalan.processor.TransformerFactoryImpl()).newInstance();).
Performance is worse than XSLTC but much better than no cache.
Unfortunately
we have exactly the same memory problem as with XSLTC.
The specs of our environment: Server: Pentium III, 850 Mhz, 256 MB RAM,
Windows 2000, JDK 1.4, Tomcat 4.0.3, Xalan 2.4.0
As far as I understand the templates interface it should be much more
memory
efficient to cache the stylesheets than doing transformation without
caching. We would be really glad if someone has an idea what could be
wrong.
A bug in the cache? A bug in Tomcat, Xalan? To big stylesheets?
Thanks in advance,
Flo
--------------
Stylesheet cache:
package edu.tum.cs.olev;
import java.util.HashMap;
import java.util.Date;
import java.util.Collection;
import java.util.Set;
import java.text.DecimalFormat;
import java.io.File;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
/**
* This class implements a XSLT stylesheet cache. Since this class is NOT
thread-safe, methods
* must not be called by any object except the
<code>Config</code>-singleton.
* Again: Although all methods are explained they are not supposed to be
called from any class
* other than <code>Config</code>. <code>Config</code> provides methods to
access all features
* of the cache.<br />
* This class is based on <code>StylesheetCache.java</code> from "Java and
XSLT" by Eric M. Burke
* (O'Reilly).
* @see Config
* @version $Revision: 1.5 $, Date: $Date: 2002/10/13 17:09:36 $
* @author $Author: deissenb $
* @author ‹-- last modification | A. Freyschmidt, F. Deissenboeck,
S.
Winter
*/
public class XSLTCache {
/** counts cache hits */
private double cacheHits=0;
/** counts requests */
private double requests=0;
/** the actual cache */
private HashMap cache = new HashMap();
/** time of last flus */
private Date lastFlushed;
private TransformerFactory transformerFactory;
protected XSLTCache() {
//XSLTC
//transformerFactory =
// (new
org.apache.xalan.xsltc.trax.TransformerFactoryImpl()).newInstance();
//classic
transformerFactory =
(new
org.apache.xalan.processor.TransformerFactoryImpl()).newInstance();
}
/**
* Flushes the whole cache.
*/
private void flushAll() {
requests = 0;
cacheHits = 0;
cache.clear();
lastFlushed = new Date();
}
/**
* This is the method to obtain a cached version of a stylesheet. If no
cached version is present
* this method sets up a new <code>Transformer</code>. The method uses
the
<code>Templates</code>-
* interface for stylesheet caching. <br />
* @param xsltFilename the filename of the stylesheet. The method expects
the pure filename without
* any path information
* @return a <code>Transfomer</code>
* @throws TransformerConfigurationException
*/
protected Transformer getTransformer(String xsltFilename)
throws TransformerConfigurationException {
//increase hits
requests++;
//increase hits in every case
cacheHits++;
//store XSLT
File xslt = new File(Config.getInstance().getXSLTPath(xsltFilename));
//get entry from cache
Templates entry = (Templates)cache.get(xsltFilename);
//we don't have cached version
if (entry == null) {
//this is no cache hit
cacheHits--;
StreamSource source = new StreamSource(xslt);
entry = transformerFactory.newTemplates(source);
//store it in the cache
cache.put(xsltFilename, entry);
}
//now we have entry anyway, get the Transformer
return entry.newTransformer();
}
/**
* This method returns a string containing minimal status information
about the cache.
* The information string look like this<br />
* <code>Cache info: Requests: 8.0, Hits: 5.0, Ratio: 0,62, # entries: 3,
* last flush: Tue Oct 08 18:34:06 CEST 2002</code>
* @return the information string
*/
protected String getCacheInfo() {
DecimalFormat format = new DecimalFormat("0.00");
String info = "Cache info: Requests: " + requests + ", Hits: " +
cacheHits + ", Ratio: " + format.format(cacheHits/requests)
+ ", # entries: " + cache.size() + ", last flush: " + lastFlushed;
return info;
}
/**
* Returns the names of all cache entries (the file names)
*/
protected Set getEntryNames() {
return cache.keySet();
}
}