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