6 hours and many cups of coffee later, I realized that the developer that had written this application was using JAXB to marshal / un-marshal XML from a web service end point. As per the API example, the developer was creating a JAXB context for every message in this manner:
StringWriter sw = new StringWriter(); JAXBContext jaxbContext = JAXBContext.newInstance(myObject.getClass()); Marshaller marshal = jaxbContext.createMarshaller(); marshal.marshal(myObject, sw);
A new JAXB context was getting created every single time a web service message was sent/received! There is a known memory leak issue when using the JAXB context in this manner. Check out the While One Fork blog for more information.
I ended up creating a JAXBContextFactory class that allows the JAXBContext to be cached and reused. Find the code below. We redeployed the code and voila - the memory issues disappeared!
package my.mypackage.jaxb;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
public class JAXBContextFactory {
private static JAXBContextFactory instance = new JAXBContextFactory();
private static final Map< String, JAXBContext > instances = new ConcurrentHashMap< String, JAXBContext >();
private JAXBContextFactory() {
}
/**
* Returns an existing JAXBContext if one for the particular namespace exists,
* else it creates an instance adds it to a internal map.
* @param contextPath the context path
* @throws JAXBException exception in creating context
* @return a created JAXBContext
*/
public JAXBContext getJaxBContext(final String contextPath) throws JAXBException {
JAXBContext context = instances.get(contextPath);
if (context == null) {
context = JAXBContext.newInstance(contextPath);
instances.put(contextPath, context);
}
return context;
}
/**
* Returns an existing JAXBContext if one for the particular namespace exists,
* else it creates an instance adds it to a internal map.
* @param contextPath the context path
* @throws JAXBException exception in creating context
* @return a created JAXBContext
*/
public JAXBContext getJaxBContext(final Class contextPath) throws JAXBException {
JAXBContext context = instances.get(contextPath.getName());
if (context == null) {
context = JAXBContext.newInstance(contextPath);
instances.put(contextPath.getName(), context);
}
return context;
}
/**
* Get instance.
* @return Instance of this factory
*/
public static JAXBContextFactory getInstance() {
return instance;
}
}
Here is how to use it in your application:
StringWriter sw = new StringWriter(); JAXBContextFactory factory = JAXBContextFactory.getInstance(); JAXBContext context = factory.getJaxBContext(MyClass.class); Marshaller marshal = jaxbContext.createMarshaller(); marshal.marshal(myObject, sw);
No comments:
Post a Comment